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.

1040 lines
37 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,
  26. coordUser *til.User) (*TxSelector, *historydb.HistoryDB) {
  27. pass := os.Getenv("POSTGRES_PASS")
  28. db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
  29. require.NoError(t, err)
  30. l2DB := l2db.NewL2DB(db, db, 10, 100, 0.0, 24*time.Hour, nil)
  31. historyDB := historydb.NewHistoryDB(db, db, nil)
  32. dir, err := ioutil.TempDir("", "tmpdb")
  33. require.NoError(t, err)
  34. defer assert.NoError(t, os.RemoveAll(dir))
  35. syncStateDB, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  36. Type: statedb.TypeTxSelector, NLevels: 0})
  37. require.NoError(t, err)
  38. txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
  39. require.NoError(t, err)
  40. defer assert.NoError(t, os.RemoveAll(dir))
  41. // use Til Coord keys for tests compatibility
  42. coordAccount := &CoordAccount{
  43. Addr: coordUser.Addr,
  44. BJJ: coordUser.BJJ.Public().Compress(),
  45. AccountCreationAuth: nil,
  46. }
  47. // fmt.Printf("%v\n", coordAccount)
  48. auth := common.AccountCreationAuth{
  49. EthAddr: coordUser.Addr,
  50. BJJ: coordUser.BJJ.Public().Compress(),
  51. }
  52. err = auth.Sign(func(hash []byte) ([]byte, error) {
  53. return ethCrypto.Sign(hash, coordUser.EthSk)
  54. }, chainID, hermezContractAddr)
  55. assert.NoError(t, err)
  56. coordAccount.AccountCreationAuth = auth.Signature
  57. txsel, err := NewTxSelector(coordAccount, txselDir, syncStateDB, l2DB)
  58. require.NoError(t, err)
  59. test.WipeDB(txsel.l2db.DB())
  60. return txsel, historyDB
  61. }
  62. func addAccCreationAuth(t *testing.T, tc *til.Context, txsel *TxSelector, chainID uint16,
  63. hermezContractAddr ethCommon.Address, username string) []byte {
  64. user := tc.Users[username]
  65. auth := &common.AccountCreationAuth{
  66. EthAddr: user.Addr,
  67. BJJ: user.BJJ.Public().Compress(),
  68. }
  69. err := auth.Sign(func(hash []byte) ([]byte, error) {
  70. return ethCrypto.Sign(hash, user.EthSk)
  71. }, chainID, hermezContractAddr)
  72. assert.NoError(t, err)
  73. err = txsel.l2db.AddAccountCreationAuth(auth)
  74. assert.NoError(t, err)
  75. return auth.Signature
  76. }
  77. func addL2Txs(t *testing.T, txsel *TxSelector, poolL2Txs []common.PoolL2Tx) {
  78. for i := 0; i < len(poolL2Txs); i++ {
  79. err := txsel.l2db.AddTxTest(&poolL2Txs[i])
  80. if err != nil {
  81. log.Error(err)
  82. }
  83. require.NoError(t, err)
  84. }
  85. }
  86. func addTokens(t *testing.T, tc *til.Context, db *sqlx.DB) {
  87. var tokens []common.Token
  88. for i := 0; i < int(tc.LastRegisteredTokenID); i++ {
  89. tokens = append(tokens, common.Token{
  90. TokenID: common.TokenID(i + 1),
  91. EthBlockNum: 1,
  92. EthAddr: ethCommon.BytesToAddress([]byte{byte(i + 1)}),
  93. Name: strconv.Itoa(i),
  94. Symbol: strconv.Itoa(i),
  95. Decimals: 18,
  96. })
  97. }
  98. hdb := historydb.NewHistoryDB(db, db, nil)
  99. assert.NoError(t, hdb.AddBlock(&common.Block{
  100. Num: 1,
  101. }))
  102. assert.NoError(t, hdb.AddTokens(tokens))
  103. }
  104. func checkBalance(t *testing.T, tc *til.Context, txsel *TxSelector, username string,
  105. tokenid int, expected string) {
  106. // Accounts.Idx does not match with the TxSelector tests as we are not
  107. // using the Til L1CoordinatorTxs (as are generated by the TxSelector
  108. // itself when processing the txs, so the Idxs does not match the Til
  109. // idxs). But the Idx is obtained through StateDB.GetIdxByEthAddrBJJ
  110. user := tc.Users[username]
  111. idx, err := txsel.localAccountsDB.GetIdxByEthAddrBJJ(user.Addr, user.BJJ.Public().Compress(),
  112. common.TokenID(tokenid))
  113. require.NoError(t, err)
  114. checkBalanceByIdx(t, txsel, idx, expected)
  115. }
  116. func checkBalanceByIdx(t *testing.T, txsel *TxSelector, idx common.Idx, expected string) {
  117. acc, err := txsel.localAccountsDB.GetAccount(idx)
  118. require.NoError(t, err)
  119. assert.Equal(t, expected, acc.Balance.String())
  120. }
  121. // checkSortedByNonce takes as input testAccNonces map, and the array of
  122. // common.PoolL2Txs, and checks if the nonces correspond to the accumulated
  123. // values of the map. Also increases the Nonces computed on the map.
  124. func checkSortedByNonce(t *testing.T, testAccNonces map[common.Idx]common.Nonce,
  125. txs []common.PoolL2Tx) {
  126. for _, tx := range txs {
  127. assert.True(t, testAccNonces[tx.FromIdx] == tx.Nonce,
  128. fmt.Sprintf("Idx: %d, expected: %d, tx.Nonce: %d",
  129. tx.FromIdx, testAccNonces[tx.FromIdx], tx.Nonce))
  130. testAccNonces[tx.FromIdx] = testAccNonces[tx.FromIdx] + 1
  131. }
  132. }
  133. func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
  134. chainID := uint16(0)
  135. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  136. // generate test transactions, the L1CoordinatorTxs generated by Til
  137. // will be ignored at this test, as will be the TxSelector who
  138. // generates them when needed
  139. blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
  140. assert.NoError(t, err)
  141. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  142. txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  143. // restart nonces of TilContext, as will be set by generating directly
  144. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  145. tc.RestartNonces()
  146. testAccNonces := make(map[common.Idx]common.Nonce)
  147. // add tokens to HistoryDB to avoid breaking FK constrains
  148. addTokens(t, tc, txsel.l2db.DB())
  149. tpc := txprocessor.Config{
  150. NLevels: 16,
  151. MaxFeeTx: 10,
  152. MaxTx: 20,
  153. MaxL1Tx: 10,
  154. ChainID: chainID,
  155. }
  156. // coordIdxs, accAuths, l1UserTxs, l1CoordTxs, l2Txs, err
  157. log.Debug("block:0 batch:1")
  158. l1UserTxs := []common.L1Tx{}
  159. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err :=
  160. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  161. require.NoError(t, err)
  162. assert.Equal(t, 0, len(oL1UserTxs))
  163. assert.Equal(t, 0, len(oL1CoordTxs))
  164. assert.Equal(t, 0, len(oL2Txs))
  165. assert.Equal(t, common.BatchNum(1), txsel.localAccountsDB.CurrentBatch())
  166. assert.Equal(t, common.Idx(255), txsel.localAccountsDB.CurrentIdx())
  167. log.Debug("block:0 batch:2")
  168. l1UserTxs = []common.L1Tx{}
  169. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
  170. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  171. require.NoError(t, err)
  172. assert.Equal(t, 0, len(oL1UserTxs))
  173. assert.Equal(t, 0, len(oL1CoordTxs))
  174. assert.Equal(t, 0, len(oL2Txs))
  175. assert.Equal(t, common.BatchNum(2), txsel.localAccountsDB.CurrentBatch())
  176. assert.Equal(t, common.Idx(255), txsel.localAccountsDB.CurrentIdx())
  177. log.Debug("block:0 batch:3")
  178. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
  179. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
  180. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  181. require.NoError(t, err)
  182. assert.Equal(t, 2, len(oL1UserTxs))
  183. assert.Equal(t, 0, len(oL1CoordTxs))
  184. assert.Equal(t, 0, len(oL2Txs))
  185. assert.Equal(t, common.BatchNum(3), txsel.localAccountsDB.CurrentBatch())
  186. assert.Equal(t, common.Idx(257), txsel.localAccountsDB.CurrentIdx())
  187. checkBalance(t, tc, txsel, "A", 0, "500")
  188. checkBalance(t, tc, txsel, "C", 1, "0")
  189. log.Debug("block:0 batch:4")
  190. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
  191. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
  192. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  193. require.NoError(t, err)
  194. assert.Equal(t, 1, len(oL1UserTxs))
  195. assert.Equal(t, 0, len(oL1CoordTxs))
  196. assert.Equal(t, 0, len(oL2Txs))
  197. assert.Equal(t, common.BatchNum(4), txsel.localAccountsDB.CurrentBatch())
  198. assert.Equal(t, common.Idx(258), txsel.localAccountsDB.CurrentIdx())
  199. checkBalance(t, tc, txsel, "A", 0, "500")
  200. checkBalance(t, tc, txsel, "A", 1, "500")
  201. checkBalance(t, tc, txsel, "C", 1, "0")
  202. log.Debug("block:0 batch:5")
  203. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
  204. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
  205. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  206. require.NoError(t, err)
  207. assert.Equal(t, 0, len(oL1UserTxs))
  208. assert.Equal(t, 0, len(oL1CoordTxs))
  209. assert.Equal(t, 0, len(oL2Txs))
  210. assert.Equal(t, common.BatchNum(5), txsel.localAccountsDB.CurrentBatch())
  211. assert.Equal(t, common.Idx(258), txsel.localAccountsDB.CurrentIdx())
  212. checkBalance(t, tc, txsel, "A", 0, "500")
  213. checkBalance(t, tc, txsel, "A", 1, "500")
  214. checkBalance(t, tc, txsel, "C", 1, "0")
  215. log.Debug("block:0 batch:6")
  216. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
  217. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
  218. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  219. require.NoError(t, err)
  220. assert.Equal(t, 1, len(oL1UserTxs))
  221. assert.Equal(t, 0, len(oL1CoordTxs))
  222. assert.Equal(t, 0, len(oL2Txs))
  223. assert.Equal(t, common.BatchNum(6), txsel.localAccountsDB.CurrentBatch())
  224. assert.Equal(t, common.Idx(259), txsel.localAccountsDB.CurrentIdx())
  225. checkBalance(t, tc, txsel, "A", 0, "600")
  226. checkBalance(t, tc, txsel, "A", 1, "500")
  227. checkBalance(t, tc, txsel, "B", 0, "400")
  228. checkBalance(t, tc, txsel, "C", 1, "0")
  229. log.Debug("block:0 batch:7")
  230. // simulate the PoolL2Txs of the batch7
  231. batchPoolL2 := `
  232. Type: PoolL2
  233. PoolTransferToEthAddr(1) A-B: 200 (126)
  234. PoolTransferToEthAddr(0) B-C: 100 (126)`
  235. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  236. require.NoError(t, err)
  237. // add AccountCreationAuths that will be used at the next batch
  238. accAuthSig0 := addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "B")
  239. accAuthSig1 := addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "C")
  240. // add the PoolL2Txs to the l2DB
  241. addL2Txs(t, txsel, poolL2Txs)
  242. // check signatures of L2Txs from the L2DB (to check that the
  243. // parameters of the PoolL2Tx match the original parameters signed
  244. // before inserting it to the L2DB)
  245. l2TxsFromDB, err := txsel.l2db.GetPendingTxs()
  246. require.NoError(t, err)
  247. assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
  248. assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
  249. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
  250. coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
  251. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  252. require.NoError(t, err)
  253. assert.Equal(t, []common.Idx{261, 263}, coordIdxs)
  254. assert.Equal(t, txsel.coordAccount.AccountCreationAuth, accAuths[0])
  255. assert.Equal(t, txsel.coordAccount.AccountCreationAuth, accAuths[2])
  256. assert.Equal(t, accAuthSig0, accAuths[1])
  257. assert.Equal(t, accAuthSig1, accAuths[3])
  258. assert.Equal(t, 1, len(oL1UserTxs))
  259. assert.Equal(t, 4, len(oL1CoordTxs))
  260. assert.Equal(t, 2, len(oL2Txs))
  261. assert.Equal(t, 0, len(discardedL2Txs))
  262. assert.Equal(t, len(oL1CoordTxs), len(accAuths))
  263. assert.Equal(t, common.BatchNum(7), txsel.localAccountsDB.CurrentBatch())
  264. assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
  265. checkBalance(t, tc, txsel, "Coord", 1, "20") // CoordIdx for TokenID=1
  266. checkBalance(t, tc, txsel, "Coord", 0, "10") // CoordIdx for TokenID=1
  267. checkBalance(t, tc, txsel, "A", 0, "600")
  268. checkBalance(t, tc, txsel, "A", 1, "280")
  269. checkBalance(t, tc, txsel, "B", 0, "290")
  270. checkBalance(t, tc, txsel, "B", 1, "200")
  271. checkBalance(t, tc, txsel, "C", 0, "100")
  272. checkBalance(t, tc, txsel, "D", 0, "800")
  273. checkSortedByNonce(t, testAccNonces, oL2Txs)
  274. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs),
  275. txsel.localAccountsDB.CurrentBatch())
  276. require.NoError(t, err)
  277. log.Debug("block:0 batch:8")
  278. // simulate the PoolL2Txs of the batch8
  279. batchPoolL2 = `
  280. Type: PoolL2
  281. PoolTransfer(0) A-B: 100 (126)
  282. PoolTransfer(0) C-A: 50 (126)
  283. PoolTransfer(1) B-C: 100 (126)
  284. PoolExit(0) A: 100 (126)`
  285. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  286. require.NoError(t, err)
  287. addL2Txs(t, txsel, poolL2Txs)
  288. // check signatures of L2Txs from the L2DB (to check that the
  289. // parameters of the PoolL2Tx match the original parameters signed
  290. // before inserting it to the L2DB)
  291. l2TxsFromDB, err = txsel.l2db.GetPendingTxs()
  292. require.NoError(t, err)
  293. assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
  294. assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["C"].BJJ.Public().Compress()))
  295. assert.True(t, l2TxsFromDB[2].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
  296. assert.True(t, l2TxsFromDB[3].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
  297. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
  298. coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  299. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  300. require.NoError(t, err)
  301. assert.Equal(t, []common.Idx{261, 263}, coordIdxs)
  302. assert.Equal(t, 0, len(accAuths))
  303. assert.Equal(t, 0, len(oL1UserTxs))
  304. assert.Equal(t, 0, len(oL1CoordTxs))
  305. assert.Equal(t, 4, len(oL2Txs))
  306. assert.Equal(t, 0, len(discardedL2Txs))
  307. assert.Equal(t, len(oL1CoordTxs), len(accAuths))
  308. assert.Equal(t, common.BatchNum(8), txsel.localAccountsDB.CurrentBatch())
  309. assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
  310. checkBalance(t, tc, txsel, "Coord", 1, "30") // CoordIdx for TokenID=1
  311. checkBalance(t, tc, txsel, "Coord", 0, "35") // CoordIdx for TokenID=1
  312. checkBalance(t, tc, txsel, "A", 0, "430")
  313. checkBalance(t, tc, txsel, "A", 1, "280")
  314. checkBalance(t, tc, txsel, "B", 0, "390")
  315. checkBalance(t, tc, txsel, "B", 1, "90")
  316. checkBalance(t, tc, txsel, "C", 0, "45")
  317. checkBalance(t, tc, txsel, "C", 1, "100")
  318. checkBalance(t, tc, txsel, "D", 0, "800")
  319. checkSortedByNonce(t, testAccNonces, oL2Txs)
  320. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs),
  321. txsel.localAccountsDB.CurrentBatch())
  322. require.NoError(t, err)
  323. log.Debug("(batch9)block:1 batch:1")
  324. // simulate the PoolL2Txs of the batch9
  325. batchPoolL2 = `
  326. Type: PoolL2
  327. PoolTransfer(0) D-A: 300 (126)
  328. PoolTransfer(0) B-D: 100 (126)
  329. `
  330. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  331. require.NoError(t, err)
  332. addL2Txs(t, txsel, poolL2Txs)
  333. // check signatures of L2Txs from the L2DB (to check that the
  334. // parameters of the PoolL2Tx match the original parameters signed
  335. // before inserting it to the L2DB)
  336. l2TxsFromDB, err = txsel.l2db.GetPendingTxs()
  337. require.NoError(t, err)
  338. assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["D"].BJJ.Public().Compress()))
  339. assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
  340. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
  341. coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
  342. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  343. require.NoError(t, err)
  344. assert.Equal(t, []common.Idx{263}, coordIdxs)
  345. assert.Equal(t, 0, len(accAuths))
  346. assert.Equal(t, 4, len(oL1UserTxs))
  347. assert.Equal(t, 0, len(oL1CoordTxs))
  348. assert.Equal(t, 2, len(oL2Txs))
  349. assert.Equal(t, len(oL1CoordTxs), len(accAuths))
  350. assert.Equal(t, common.BatchNum(9), txsel.localAccountsDB.CurrentBatch())
  351. assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
  352. checkBalanceByIdx(t, txsel, 261, "30")
  353. checkBalanceByIdx(t, txsel, 263, "75")
  354. checkBalance(t, tc, txsel, "A", 0, "730")
  355. checkBalance(t, tc, txsel, "A", 1, "280")
  356. checkBalance(t, tc, txsel, "B", 0, "380")
  357. checkBalance(t, tc, txsel, "B", 1, "90")
  358. checkBalance(t, tc, txsel, "C", 0, "845")
  359. checkBalance(t, tc, txsel, "C", 1, "100")
  360. checkBalance(t, tc, txsel, "D", 0, "470")
  361. checkSortedByNonce(t, testAccNonces, oL2Txs)
  362. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs),
  363. txsel.localAccountsDB.CurrentBatch())
  364. require.NoError(t, err)
  365. }
  366. func TestPoolL2TxsWithoutEnoughBalance(t *testing.T) {
  367. set := `
  368. Type: Blockchain
  369. CreateAccountDeposit(0) Coord: 0
  370. CreateAccountDeposit(0) A: 100
  371. CreateAccountDeposit(0) B: 100
  372. > batchL1 // freeze L1User{3}
  373. > batchL1 // forge L1User{3}
  374. > block
  375. `
  376. chainID := uint16(0)
  377. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  378. // generate test transactions, the L1CoordinatorTxs generated by Til
  379. // will be ignored at this test, as will be the TxSelector who
  380. // generates them when needed
  381. blocks, err := tc.GenerateBlocks(set)
  382. assert.NoError(t, err)
  383. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  384. txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  385. // restart nonces of TilContext, as will be set by generating directly
  386. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  387. tc.RestartNonces()
  388. tpc := txprocessor.Config{
  389. NLevels: 16,
  390. MaxFeeTx: 10,
  391. MaxTx: 20,
  392. MaxL1Tx: 10,
  393. ChainID: chainID,
  394. }
  395. // batch1
  396. l1UserTxs := []common.L1Tx{}
  397. _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  398. require.NoError(t, err)
  399. // 1st TransferToEthAddr
  400. expectedTxID0 := "0x028847b86613c0b70be18c8622119ed045b42e4e47d7938fa90bb3d1dc14928965"
  401. // 1st Exit
  402. expectedTxID1 := "0x0200b18773dcf56f770d65870fb02041cb59a088fd35b7c3f3df69f8a250b99a42"
  403. // 2nd TransferToEthAddr
  404. expectedTxID2 := "0x029720ff506153f970f120ac638cd7ee759eeff2c2012e7634a78e4fdc05c04a90"
  405. // batch2
  406. // prepare the PoolL2Txs
  407. batchPoolL2 := `
  408. Type: PoolL2
  409. PoolTransferToEthAddr(0) A-B: 100 (126)
  410. PoolExit(0) B: 100 (126)`
  411. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  412. require.NoError(t, err)
  413. // add the PoolL2Txs to the l2DB
  414. addL2Txs(t, txsel, poolL2Txs)
  415. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  416. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
  417. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  418. require.NoError(t, err)
  419. assert.Equal(t, 3, len(oL1UserTxs))
  420. assert.Equal(t, 0, len(oL1CoordTxs))
  421. assert.Equal(t, 0, len(oL2Txs)) // should be 0 as the 2 PoolL2Txs does not have enough funds
  422. assert.Equal(t, 2, len(discardedL2Txs))
  423. assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
  424. assert.Equal(t, expectedTxID1, discardedL2Txs[1].TxID.String())
  425. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  426. txsel.localAccountsDB.CurrentBatch())
  427. require.NoError(t, err)
  428. // as the PoolL2Txs have not been really processed, restart nonces
  429. tc.RestartNonces()
  430. // batch3
  431. batchPoolL2 = `
  432. Type: PoolL2
  433. PoolTransferToEthAddr(0) A-B: 50 (126)`
  434. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  435. require.NoError(t, err)
  436. addL2Txs(t, txsel, poolL2Txs)
  437. l1UserTxs = []common.L1Tx{}
  438. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  439. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  440. require.NoError(t, err)
  441. assert.Equal(t, 0, len(oL1UserTxs))
  442. assert.Equal(t, 0, len(oL1CoordTxs))
  443. assert.Equal(t, 2, len(oL2Txs))
  444. assert.Equal(t, 1, len(discardedL2Txs))
  445. assert.Equal(t, expectedTxID2, oL2Txs[0].TxID.String())
  446. assert.Equal(t, expectedTxID1, oL2Txs[1].TxID.String())
  447. assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
  448. assert.Equal(t, common.TxTypeTransferToEthAddr, oL2Txs[0].Type)
  449. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  450. txsel.localAccountsDB.CurrentBatch())
  451. require.NoError(t, err)
  452. // batch4
  453. // make the selection of another batch, which should include the
  454. // initial PoolExit, which now is valid as B has enough Balance
  455. l1UserTxs = []common.L1Tx{}
  456. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  457. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  458. require.NoError(t, err)
  459. assert.Equal(t, 0, len(oL1UserTxs))
  460. assert.Equal(t, 0, len(oL1CoordTxs))
  461. assert.Equal(t, 0, len(oL2Txs))
  462. assert.Equal(t, 1, len(discardedL2Txs))
  463. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  464. txsel.localAccountsDB.CurrentBatch())
  465. require.NoError(t, err)
  466. }
  467. func TestTransferToBjj(t *testing.T) {
  468. set := `
  469. Type: Blockchain
  470. AddToken(1)
  471. CreateAccountDeposit(0) Coord: 0
  472. CreateAccountDeposit(0) A: 1000
  473. CreateAccountDeposit(0) B: 1000
  474. CreateAccountDeposit(1) B: 1000
  475. > batchL1 // freeze L1User{4}
  476. > batchL1 // forge L1User{4}
  477. > block
  478. `
  479. chainID := uint16(0)
  480. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  481. blocks, err := tc.GenerateBlocks(set)
  482. assert.NoError(t, err)
  483. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  484. txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  485. // restart nonces of TilContext, as will be set by generating directly
  486. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  487. tc.RestartNonces()
  488. addTokens(t, tc, txsel.l2db.DB())
  489. tpc := txprocessor.Config{
  490. NLevels: 16,
  491. MaxFeeTx: 10,
  492. MaxTx: 20,
  493. MaxL1Tx: 10,
  494. ChainID: chainID,
  495. }
  496. // batch1 to freeze L1UserTxs that will create some accounts with
  497. // positive balance
  498. l1UserTxs := []common.L1Tx{}
  499. _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  500. require.NoError(t, err)
  501. // Transfer is ToBJJ to a BJJ-only account that doesn't exist
  502. // and the coordinator will create it via L1CoordTx.
  503. batchPoolL2 := `
  504. Type: PoolL2
  505. PoolTransferToBJJ(0) A-B: 50 (126)
  506. `
  507. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  508. require.NoError(t, err)
  509. // add the PoolL2Txs to the l2DB
  510. addL2Txs(t, txsel, poolL2Txs)
  511. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  512. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
  513. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  514. require.NoError(t, err)
  515. assert.Equal(t, 4, len(oL1UserTxs))
  516. // We expect the coordinator to add an L1CoordTx to create an account for the recipient of the l2tx
  517. require.Equal(t, 1, len(oL1CoordTxs))
  518. assert.Equal(t, poolL2Txs[0].ToEthAddr, oL1CoordTxs[0].FromEthAddr)
  519. assert.Equal(t, poolL2Txs[0].ToBJJ, oL1CoordTxs[0].FromBJJ)
  520. assert.Equal(t, 1, len(oL2Txs))
  521. assert.Equal(t, 0, len(discardedL2Txs))
  522. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  523. txsel.localAccountsDB.CurrentBatch())
  524. require.NoError(t, err)
  525. // Now the BJJ-only account for B is already created, so the transfer
  526. // happens without an L1CoordTx that creates the user account.
  527. batchPoolL2 = `
  528. Type: PoolL2
  529. PoolTransferToBJJ(0) A-B: 50 (126)
  530. `
  531. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  532. require.NoError(t, err)
  533. addL2Txs(t, txsel, poolL2Txs)
  534. l1UserTxs = []common.L1Tx{}
  535. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  536. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  537. require.NoError(t, err)
  538. assert.Equal(t, 0, len(oL1UserTxs))
  539. // Since the BJJ-only account B already exists, the coordinator doesn't add any L1CoordTxs
  540. assert.Equal(t, 0, len(oL1CoordTxs))
  541. assert.Equal(t, 1, len(oL2Txs))
  542. assert.Equal(t, 0, len(discardedL2Txs))
  543. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  544. txsel.localAccountsDB.CurrentBatch())
  545. require.NoError(t, err)
  546. // The transfer now is ToBJJ to a BJJ-only account that doesn't exist
  547. // and the coordinator will create it via L1CoordTx. Since it's a
  548. // transfer of a token for which the coordinator doesn't have a fee
  549. // account, another L1CoordTx will be created for the coordinator to
  550. // receive the fees.
  551. batchPoolL2 = `
  552. Type: PoolL2
  553. PoolTransferToBJJ(1) B-A: 50 (126)
  554. `
  555. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  556. require.NoError(t, err)
  557. addL2Txs(t, txsel, poolL2Txs)
  558. l1UserTxs = []common.L1Tx{}
  559. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  560. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  561. require.NoError(t, err)
  562. assert.Equal(t, 0, len(oL1UserTxs))
  563. // We expect the coordinator to add an L1CoordTx to create an account
  564. // to receive the fees by the coordinator and another one for the
  565. // recipient of the l2tx
  566. assert.Equal(t, 2, len(oL1CoordTxs))
  567. // [0] Coordinator account cration for token 1
  568. assert.Equal(t, tc.Users["Coord"].Addr, oL1CoordTxs[0].FromEthAddr)
  569. // [1] User A BJJ-only account creation for token 1
  570. assert.Equal(t, poolL2Txs[0].ToEthAddr, oL1CoordTxs[1].FromEthAddr)
  571. assert.Equal(t, poolL2Txs[0].ToBJJ, oL1CoordTxs[1].FromBJJ)
  572. assert.Equal(t, common.TokenID(1), oL1CoordTxs[1].TokenID)
  573. assert.Equal(t, 1, len(oL2Txs))
  574. assert.Equal(t, 0, len(discardedL2Txs))
  575. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  576. txsel.localAccountsDB.CurrentBatch())
  577. require.NoError(t, err)
  578. }
  579. func TestTransferManyFromSameAccount(t *testing.T) {
  580. set := `
  581. Type: Blockchain
  582. CreateAccountDeposit(0) Coord: 0
  583. CreateAccountDeposit(0) A: 1000
  584. CreateAccountDeposit(0) B: 1000
  585. > batchL1 // freeze L1User{3}
  586. > batchL1 // forge L1User{3}
  587. > block
  588. `
  589. chainID := uint16(0)
  590. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  591. blocks, err := tc.GenerateBlocks(set)
  592. assert.NoError(t, err)
  593. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  594. txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  595. // restart nonces of TilContext, as will be set by generating directly
  596. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  597. tc.RestartNonces()
  598. tpc := txprocessor.Config{
  599. NLevels: 16,
  600. MaxFeeTx: 10,
  601. MaxTx: 10,
  602. MaxL1Tx: 10,
  603. ChainID: chainID,
  604. }
  605. // batch1 to freeze L1UserTxs
  606. l1UserTxs := []common.L1Tx{}
  607. _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  608. require.NoError(t, err)
  609. // 8 transfers from the same account
  610. batchPoolL2 := `
  611. Type: PoolL2
  612. PoolTransfer(0) A-B: 10 (126) // 1
  613. PoolTransfer(0) A-B: 10 (126) // 2
  614. PoolTransfer(0) A-B: 10 (126) // 3
  615. PoolTransfer(0) A-B: 10 (126) // 4
  616. PoolTransfer(0) A-B: 10 (126) // 5
  617. PoolTransfer(0) A-B: 10 (126) // 6
  618. PoolTransfer(0) A-B: 10 (126) // 7
  619. PoolTransfer(0) A-B: 10 (126) // 8
  620. PoolTransfer(0) A-B: 10 (126) // 9
  621. PoolTransfer(0) A-B: 10 (126) // 10
  622. PoolTransfer(0) A-B: 10 (126) // 11
  623. `
  624. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  625. require.NoError(t, err)
  626. require.Equal(t, 11, len(poolL2Txs))
  627. // reorder poolL2Txs so that nonces are not sorted
  628. poolL2Txs[0], poolL2Txs[7] = poolL2Txs[7], poolL2Txs[0]
  629. poolL2Txs[1], poolL2Txs[10] = poolL2Txs[10], poolL2Txs[1]
  630. // add the PoolL2Txs to the l2DB
  631. addL2Txs(t, txsel, poolL2Txs)
  632. // batch 2 to crate some accounts with positive balance, and do 8 L2Tx
  633. // transfers from account A
  634. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  635. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
  636. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  637. require.NoError(t, err)
  638. assert.Equal(t, 3, len(oL1UserTxs))
  639. require.Equal(t, 0, len(oL1CoordTxs))
  640. assert.Equal(t, 7, len(oL2Txs))
  641. assert.Equal(t, 4, len(discardedL2Txs))
  642. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  643. txsel.localAccountsDB.CurrentBatch())
  644. require.NoError(t, err)
  645. }
  646. func TestPoolL2TxInvalidNonces(t *testing.T) {
  647. // This test recreates the case where L2Txs of type TransferToEthAddr
  648. // for non existing accounts are not selected due not enough space for
  649. // the needed L1CoordinatorTxs (of account creation).
  650. set := `
  651. Type: Blockchain
  652. CreateAccountDeposit(0) Coord: 0
  653. CreateAccountDeposit(0) A: 100000
  654. CreateAccountDeposit(0) B: 10000
  655. > batchL1 // Batch1: freeze L1User{3}
  656. > batchL1 // Batch2: forge L1User{3}
  657. > block
  658. `
  659. chainID := uint16(0)
  660. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  661. blocks, err := tc.GenerateBlocks(set)
  662. assert.NoError(t, err)
  663. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  664. txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  665. // restart nonces of TilContext, as will be set by generating directly
  666. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  667. tc.RestartNonces()
  668. tpc := txprocessor.Config{
  669. NLevels: 16,
  670. MaxFeeTx: 10,
  671. MaxTx: 20,
  672. MaxL1Tx: 3,
  673. ChainID: chainID,
  674. }
  675. // batch1 to freeze L1UserTxs
  676. l1UserTxs := []common.L1Tx{}
  677. _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  678. require.NoError(t, err)
  679. batchPoolL2 := `
  680. Type: PoolL2
  681. PoolTransferToEthAddr(0) B-C: 10 (126)
  682. PoolTransfer(0) B-A: 10 (126)
  683. PoolTransferToEthAddr(0) B-D: 10 (126)
  684. PoolTransfer(0) B-A: 10 (126)
  685. PoolTransferToEthAddr(0) B-E: 10 (126)
  686. PoolTransfer(0) B-A: 10 (126)
  687. PoolTransferToEthAddr(0) B-F: 10 (126)
  688. PoolTransfer(0) B-A: 10 (126)
  689. PoolTransferToEthAddr(0) B-G: 10 (126)
  690. PoolTransfer(0) B-A: 10 (126)
  691. `
  692. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  693. require.NoError(t, err)
  694. require.Equal(t, 10, len(poolL2Txs))
  695. // add AccountCreationAuths that will be used at the next batch
  696. _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "C")
  697. _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "D")
  698. _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "E")
  699. _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "F")
  700. _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "G")
  701. // add the PoolL2Txs to the l2DB
  702. addL2Txs(t, txsel, poolL2Txs)
  703. // batch 2 to crate the accounts (from L1UserTxs)
  704. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  705. // select L1 & L2 txs
  706. _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
  707. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  708. require.NoError(t, err)
  709. require.Equal(t, 3, len(oL1UserTxs))
  710. require.Equal(t, 0, len(oL1CoordTxs))
  711. require.Equal(t, 0, len(oL2Txs))
  712. require.Equal(t, 10, len(discardedL2Txs))
  713. require.Equal(t, 0, len(accAuths))
  714. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  715. txsel.localAccountsDB.CurrentBatch())
  716. require.NoError(t, err)
  717. // batch 3
  718. l1UserTxs = []common.L1Tx{}
  719. _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  720. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  721. require.NoError(t, err)
  722. require.Equal(t, 0, len(oL1UserTxs))
  723. require.Equal(t, 3, len(oL1CoordTxs))
  724. require.Equal(t, 8, len(oL2Txs))
  725. require.Equal(t, 2, len(discardedL2Txs))
  726. require.Equal(t, 3, len(accAuths))
  727. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  728. txsel.localAccountsDB.CurrentBatch())
  729. require.NoError(t, err)
  730. // batch 4
  731. l1UserTxs = []common.L1Tx{}
  732. _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  733. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  734. require.NoError(t, err)
  735. require.Equal(t, 0, len(oL1UserTxs))
  736. require.Equal(t, 1, len(oL1CoordTxs))
  737. require.Equal(t, 2, len(oL2Txs))
  738. require.Equal(t, 0, len(discardedL2Txs))
  739. require.Equal(t, 1, len(accAuths))
  740. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  741. txsel.localAccountsDB.CurrentBatch())
  742. require.NoError(t, err)
  743. }
  744. func TestProcessL2Selection(t *testing.T) {
  745. set := `
  746. Type: Blockchain
  747. CreateAccountDeposit(0) Coord: 0
  748. CreateAccountDeposit(0) A: 18
  749. CreateAccountDeposit(0) B: 0
  750. > batchL1 // freeze L1User{3}
  751. > batchL1 // forge L1User{3}
  752. > block
  753. `
  754. chainID := uint16(0)
  755. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  756. blocks, err := tc.GenerateBlocks(set)
  757. assert.NoError(t, err)
  758. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  759. txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  760. // restart nonces of TilContext, as will be set by generating directly
  761. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  762. tc.RestartNonces()
  763. tpc := txprocessor.Config{
  764. NLevels: 16,
  765. MaxFeeTx: 10,
  766. MaxTx: 10,
  767. MaxL1Tx: 10,
  768. ChainID: chainID,
  769. }
  770. // batch1 to freeze L1UserTxs
  771. l1UserTxs := []common.L1Tx{}
  772. _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  773. require.NoError(t, err)
  774. // 8 transfers from the same account
  775. batchPoolL2 := `
  776. Type: PoolL2
  777. PoolTransfer(0) A-B: 10 (126)
  778. PoolTransfer(0) A-B: 10 (126) // not enough funds
  779. PoolTransfer(0) A-B: 5 (126) // enough funds
  780. `
  781. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  782. require.NoError(t, err)
  783. require.Equal(t, 3, len(poolL2Txs))
  784. // add the PoolL2Txs to the l2DB
  785. addL2Txs(t, txsel, poolL2Txs)
  786. // batch 2 to crate some accounts with positive balance, and do 8 L2Tx transfers from account A
  787. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  788. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
  789. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  790. require.NoError(t, err)
  791. assert.Equal(t, 3, len(oL1UserTxs))
  792. require.Equal(t, 0, len(oL1CoordTxs))
  793. // only 1st L2Tx should be accepted, as:
  794. // - 2nd will not be selected as has not enough funds
  795. // - 3rd will not be selected as has Nonce=2, and the account Nonce==1
  796. // (due the 2nd txs not being accepted)
  797. assert.Equal(t, 1, len(oL2Txs))
  798. assert.Equal(t, 2, len(discardedL2Txs))
  799. assert.Equal(t, common.Nonce(0), oL2Txs[0].Nonce)
  800. assert.Equal(t, common.Nonce(1), discardedL2Txs[0].Nonce)
  801. assert.Equal(t, common.Nonce(2), discardedL2Txs[1].Nonce)
  802. assert.Equal(t, "Tx not selected due to not enough Balance at the sender. "+
  803. "Current sender account Balance: 7, Amount+Fee: 11", discardedL2Txs[0].Info)
  804. assert.Equal(t, "Tx not selected due to not current Nonce. Tx.Nonce: 2, "+
  805. "Account.Nonce: 1", discardedL2Txs[1].Info)
  806. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  807. txsel.localAccountsDB.CurrentBatch())
  808. require.NoError(t, err)
  809. }
  810. func TestValidTxsWithLowFeeAndInvalidTxsWithHighFee(t *testing.T) {
  811. // This test recreates the case where there are
  812. set := `
  813. Type: Blockchain
  814. CreateAccountDeposit(0) Coord: 0
  815. CreateAccountDeposit(0) A: 100
  816. CreateAccountDeposit(0) B: 0
  817. > batchL1 // Batch1: freeze L1User{3}
  818. > batchL1 // Batch2: forge L1User{3}
  819. > block
  820. `
  821. chainID := uint16(0)
  822. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  823. tilCfgExtra := til.ConfigExtra{
  824. BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
  825. CoordUser: "Coord",
  826. }
  827. blocks, err := tc.GenerateBlocks(set)
  828. require.NoError(t, err)
  829. err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
  830. require.NoError(t, err)
  831. err = tc.FillBlocksForgedL1UserTxs(blocks)
  832. require.NoError(t, err)
  833. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  834. txsel, historyDB := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  835. // Insert blocks into DB
  836. for i := range blocks {
  837. err = historyDB.AddBlockSCData(&blocks[i])
  838. assert.NoError(t, err)
  839. }
  840. err = historyDB.UpdateTokenValue(common.EmptyAddr, 1000)
  841. require.NoError(t, err)
  842. // restart nonces of TilContext, as will be set by generating directly
  843. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  844. tc.RestartNonces()
  845. tpc := txprocessor.Config{
  846. NLevels: 16,
  847. MaxFeeTx: 5,
  848. MaxTx: 5,
  849. MaxL1Tx: 3,
  850. ChainID: chainID,
  851. }
  852. // batch1 to freeze L1UserTxs
  853. l1UserTxs := []common.L1Tx{}
  854. _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  855. require.NoError(t, err)
  856. // batch 2 to crate the accounts (from L1UserTxs)
  857. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  858. // select L1 & L2 txs
  859. _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
  860. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  861. require.NoError(t, err)
  862. require.Equal(t, 3, len(oL1UserTxs))
  863. require.Equal(t, 0, len(oL1CoordTxs))
  864. require.Equal(t, 0, len(oL2Txs))
  865. require.Equal(t, 0, len(discardedL2Txs))
  866. require.Equal(t, 0, len(accAuths))
  867. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  868. txsel.localAccountsDB.CurrentBatch())
  869. require.NoError(t, err)
  870. // batch 3. The A-B txs have lower fee, but are the only ones possible
  871. // with the current Accounts Balances, as the B-A tx of amount 40 will
  872. // not be included as will be processed first when there is not enough
  873. // balance at B (processed first as the TxSelector sorts by Fee and then
  874. // by Nonce).
  875. batchPoolL2 := `
  876. Type: PoolL2
  877. PoolTransfer(0) B-A: 40 (130) // B-A txs are only possible once A-B txs are processed
  878. PoolTransfer(0) B-A: 1 (126)
  879. PoolTransfer(0) B-A: 1 (126)
  880. PoolTransfer(0) B-A: 1 (126)
  881. PoolTransfer(0) B-A: 1 (126)
  882. PoolTransfer(0) B-A: 1 (126)
  883. PoolTransfer(0) B-A: 1 (126)
  884. PoolTransfer(0) B-A: 1 (126)
  885. PoolTransfer(0) A-B: 20 (20)
  886. PoolTransfer(0) A-B: 25 (150)
  887. PoolTransfer(0) A-B: 20 (20)
  888. `
  889. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  890. require.NoError(t, err)
  891. require.Equal(t, 11, len(poolL2Txs))
  892. // add the PoolL2Txs to the l2DB
  893. addL2Txs(t, txsel, poolL2Txs)
  894. l1UserTxs = []common.L1Tx{}
  895. _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  896. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  897. require.NoError(t, err)
  898. require.Equal(t, 0, len(oL1UserTxs))
  899. require.Equal(t, 0, len(oL1CoordTxs))
  900. require.Equal(t, 3, len(oL2Txs)) // the 3 txs A-B
  901. require.Equal(t, 8, len(discardedL2Txs)) // the 8 txs B-A
  902. require.Equal(t, 0, len(accAuths))
  903. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  904. txsel.localAccountsDB.CurrentBatch())
  905. require.NoError(t, err)
  906. // batch 4. In this Batch, account B has enough balance to send the txs
  907. _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  908. txsel.GetL1L2TxSelection(tpc, l1UserTxs)
  909. require.NoError(t, err)
  910. require.Equal(t, 0, len(oL1UserTxs))
  911. require.Equal(t, 0, len(oL1CoordTxs))
  912. require.Equal(t, 5, len(oL2Txs))
  913. require.Equal(t, 3, len(discardedL2Txs))
  914. require.Equal(t, 0, len(accAuths))
  915. }