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.

630 lines
25 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(statedb.Config{Path: dir, Keep: 128,
  34. Type: statedb.TypeTxSelector, NLevels: 0})
  35. require.NoError(t, err)
  36. txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
  37. require.NoError(t, err)
  38. defer assert.NoError(t, os.RemoveAll(dir))
  39. // use Til Coord keys for tests compatibility
  40. coordAccount := &CoordAccount{
  41. Addr: coordUser.Addr,
  42. BJJ: coordUser.BJJ.Public().Compress(),
  43. AccountCreationAuth: nil,
  44. }
  45. // fmt.Printf("%v\n", coordAccount)
  46. auth := common.AccountCreationAuth{
  47. EthAddr: coordUser.Addr,
  48. BJJ: coordUser.BJJ.Public().Compress(),
  49. }
  50. err = auth.Sign(func(hash []byte) ([]byte, error) {
  51. return ethCrypto.Sign(hash, coordUser.EthSk)
  52. }, chainID, hermezContractAddr)
  53. assert.NoError(t, err)
  54. coordAccount.AccountCreationAuth = auth.Signature
  55. txsel, err := NewTxSelector(coordAccount, txselDir, syncStateDB, l2DB)
  56. require.NoError(t, err)
  57. test.WipeDB(txsel.l2db.DB())
  58. return txsel
  59. }
  60. func addAccCreationAuth(t *testing.T, tc *til.Context, txsel *TxSelector, chainID uint16, hermezContractAddr ethCommon.Address, username string) []byte {
  61. user := tc.Users[username]
  62. auth := &common.AccountCreationAuth{
  63. EthAddr: user.Addr,
  64. BJJ: user.BJJ.Public().Compress(),
  65. }
  66. err := auth.Sign(func(hash []byte) ([]byte, error) {
  67. return ethCrypto.Sign(hash, user.EthSk)
  68. }, chainID, hermezContractAddr)
  69. assert.NoError(t, err)
  70. err = txsel.l2db.AddAccountCreationAuth(auth)
  71. assert.NoError(t, err)
  72. return auth.Signature
  73. }
  74. func addL2Txs(t *testing.T, txsel *TxSelector, poolL2Txs []common.PoolL2Tx) {
  75. for i := 0; i < len(poolL2Txs); i++ {
  76. err := txsel.l2db.AddTxTest(&poolL2Txs[i])
  77. if err != nil {
  78. log.Error(err)
  79. }
  80. require.NoError(t, err)
  81. }
  82. }
  83. func addTokens(t *testing.T, tc *til.Context, db *sqlx.DB) {
  84. var tokens []common.Token
  85. for i := 0; i < int(tc.LastRegisteredTokenID); i++ {
  86. tokens = append(tokens, common.Token{
  87. TokenID: common.TokenID(i + 1),
  88. EthBlockNum: 1,
  89. EthAddr: ethCommon.BytesToAddress([]byte{byte(i + 1)}),
  90. Name: strconv.Itoa(i),
  91. Symbol: strconv.Itoa(i),
  92. Decimals: 18,
  93. })
  94. }
  95. hdb := historydb.NewHistoryDB(db, nil)
  96. assert.NoError(t, hdb.AddBlock(&common.Block{
  97. Num: 1,
  98. }))
  99. assert.NoError(t, hdb.AddTokens(tokens))
  100. }
  101. func checkBalance(t *testing.T, tc *til.Context, txsel *TxSelector, username string, tokenid int, expected string) {
  102. // Accounts.Idx does not match with the TxSelector tests as we are not
  103. // using the Til L1CoordinatorTxs (as are generated by the TxSelector
  104. // itself when processing the txs, so the Idxs does not match the Til
  105. // idxs). But the Idx is obtained through StateDB.GetIdxByEthAddrBJJ
  106. user := tc.Users[username]
  107. idx, err := txsel.localAccountsDB.GetIdxByEthAddrBJJ(user.Addr, user.BJJ.Public().Compress(), common.TokenID(tokenid))
  108. require.NoError(t, err)
  109. checkBalanceByIdx(t, txsel, idx, expected)
  110. }
  111. func checkBalanceByIdx(t *testing.T, txsel *TxSelector, idx common.Idx, expected string) {
  112. acc, err := txsel.localAccountsDB.GetAccount(idx)
  113. require.NoError(t, err)
  114. assert.Equal(t, expected, acc.Balance.String())
  115. }
  116. // checkSortedByNonce takes as input testAccNonces map, and the array of
  117. // common.PoolL2Txs, and checks if the nonces correspond to the accumulated
  118. // values of the map. Also increases the Nonces computed on the map.
  119. func checkSortedByNonce(t *testing.T, testAccNonces map[common.Idx]common.Nonce, txs []common.PoolL2Tx) {
  120. for _, tx := range txs {
  121. assert.True(t, testAccNonces[tx.FromIdx] == tx.Nonce,
  122. fmt.Sprintf("Idx: %d, expected: %d, tx.Nonce: %d",
  123. tx.FromIdx, testAccNonces[tx.FromIdx], tx.Nonce))
  124. testAccNonces[tx.FromIdx] = testAccNonces[tx.FromIdx] + 1
  125. }
  126. }
  127. func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
  128. chainID := uint16(0)
  129. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  130. // generate test transactions, the L1CoordinatorTxs generated by Til
  131. // will be ignored at this test, as will be the TxSelector who
  132. // generates them when needed
  133. blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
  134. assert.NoError(t, err)
  135. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  136. txsel := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  137. // restart nonces of TilContext, as will be set by generating directly
  138. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  139. tc.RestartNonces()
  140. testAccNonces := make(map[common.Idx]common.Nonce)
  141. // add tokens to HistoryDB to avoid breaking FK constrains
  142. addTokens(t, tc, txsel.l2db.DB())
  143. tpc := txprocessor.Config{
  144. NLevels: 16,
  145. MaxFeeTx: 10,
  146. MaxTx: 20,
  147. MaxL1Tx: 10,
  148. ChainID: chainID,
  149. }
  150. selectionConfig := &SelectionConfig{
  151. MaxL1UserTxs: 5,
  152. TxProcessorConfig: tpc,
  153. }
  154. // coordIdxs, accAuths, l1UserTxs, l1CoordTxs, l2Txs, err
  155. log.Debug("block:0 batch:1")
  156. l1UserTxs := []common.L1Tx{}
  157. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  158. require.NoError(t, err)
  159. assert.Equal(t, 0, len(oL1UserTxs))
  160. assert.Equal(t, 0, len(oL1CoordTxs))
  161. assert.Equal(t, 0, len(oL2Txs))
  162. assert.Equal(t, common.BatchNum(1), txsel.localAccountsDB.CurrentBatch())
  163. assert.Equal(t, common.Idx(255), txsel.localAccountsDB.CurrentIdx())
  164. log.Debug("block:0 batch:2")
  165. l1UserTxs = []common.L1Tx{}
  166. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  167. require.NoError(t, err)
  168. assert.Equal(t, 0, len(oL1UserTxs))
  169. assert.Equal(t, 0, len(oL1CoordTxs))
  170. assert.Equal(t, 0, len(oL2Txs))
  171. assert.Equal(t, common.BatchNum(2), txsel.localAccountsDB.CurrentBatch())
  172. assert.Equal(t, common.Idx(255), txsel.localAccountsDB.CurrentIdx())
  173. log.Debug("block:0 batch:3")
  174. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
  175. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  176. require.NoError(t, err)
  177. assert.Equal(t, 2, len(oL1UserTxs))
  178. assert.Equal(t, 0, len(oL1CoordTxs))
  179. assert.Equal(t, 0, len(oL2Txs))
  180. assert.Equal(t, common.BatchNum(3), txsel.localAccountsDB.CurrentBatch())
  181. assert.Equal(t, common.Idx(257), txsel.localAccountsDB.CurrentIdx())
  182. checkBalance(t, tc, txsel, "A", 0, "500")
  183. checkBalance(t, tc, txsel, "C", 1, "0")
  184. log.Debug("block:0 batch:4")
  185. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
  186. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  187. require.NoError(t, err)
  188. assert.Equal(t, 1, len(oL1UserTxs))
  189. assert.Equal(t, 0, len(oL1CoordTxs))
  190. assert.Equal(t, 0, len(oL2Txs))
  191. assert.Equal(t, common.BatchNum(4), txsel.localAccountsDB.CurrentBatch())
  192. assert.Equal(t, common.Idx(258), txsel.localAccountsDB.CurrentIdx())
  193. checkBalance(t, tc, txsel, "A", 0, "500")
  194. checkBalance(t, tc, txsel, "A", 1, "500")
  195. checkBalance(t, tc, txsel, "C", 1, "0")
  196. log.Debug("block:0 batch:5")
  197. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
  198. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  199. require.NoError(t, err)
  200. assert.Equal(t, 0, len(oL1UserTxs))
  201. assert.Equal(t, 0, len(oL1CoordTxs))
  202. assert.Equal(t, 0, len(oL2Txs))
  203. assert.Equal(t, common.BatchNum(5), txsel.localAccountsDB.CurrentBatch())
  204. assert.Equal(t, common.Idx(258), txsel.localAccountsDB.CurrentIdx())
  205. checkBalance(t, tc, txsel, "A", 0, "500")
  206. checkBalance(t, tc, txsel, "A", 1, "500")
  207. checkBalance(t, tc, txsel, "C", 1, "0")
  208. log.Debug("block:0 batch:6")
  209. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
  210. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  211. require.NoError(t, err)
  212. assert.Equal(t, 1, len(oL1UserTxs))
  213. assert.Equal(t, 0, len(oL1CoordTxs))
  214. assert.Equal(t, 0, len(oL2Txs))
  215. assert.Equal(t, common.BatchNum(6), txsel.localAccountsDB.CurrentBatch())
  216. assert.Equal(t, common.Idx(259), txsel.localAccountsDB.CurrentIdx())
  217. checkBalance(t, tc, txsel, "A", 0, "600")
  218. checkBalance(t, tc, txsel, "A", 1, "500")
  219. checkBalance(t, tc, txsel, "B", 0, "400")
  220. checkBalance(t, tc, txsel, "C", 1, "0")
  221. log.Debug("block:0 batch:7")
  222. // simulate the PoolL2Txs of the batch7
  223. batchPoolL2 := `
  224. Type: PoolL2
  225. PoolTransferToEthAddr(1) A-B: 200 (126)
  226. PoolTransferToEthAddr(0) B-C: 100 (126)`
  227. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  228. require.NoError(t, err)
  229. // add AccountCreationAuths that will be used at the next batch
  230. accAuthSig0 := addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "B")
  231. accAuthSig1 := addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "C")
  232. // add the PoolL2Txs to the l2DB
  233. addL2Txs(t, txsel, poolL2Txs)
  234. // check signatures of L2Txs from the L2DB (to check that the
  235. // parameters of the PoolL2Tx match the original parameters signed
  236. // before inserting it to the L2DB)
  237. l2TxsFromDB, err := txsel.l2db.GetPendingTxs()
  238. require.NoError(t, err)
  239. assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
  240. assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
  241. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
  242. coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  243. require.NoError(t, err)
  244. assert.Equal(t, []common.Idx{261, 262}, coordIdxs)
  245. assert.Equal(t, txsel.coordAccount.AccountCreationAuth, accAuths[0])
  246. assert.Equal(t, txsel.coordAccount.AccountCreationAuth, accAuths[1])
  247. assert.Equal(t, accAuthSig0, accAuths[2])
  248. assert.Equal(t, accAuthSig1, accAuths[3])
  249. assert.Equal(t, 1, len(oL1UserTxs))
  250. assert.Equal(t, 4, len(oL1CoordTxs))
  251. assert.Equal(t, 2, len(oL2Txs))
  252. assert.Equal(t, len(oL1CoordTxs), len(accAuths))
  253. assert.Equal(t, common.BatchNum(7), txsel.localAccountsDB.CurrentBatch())
  254. assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
  255. checkBalanceByIdx(t, txsel, 261, "20") // CoordIdx for TokenID=1
  256. checkBalanceByIdx(t, txsel, 262, "10") // CoordIdx for TokenID=0
  257. checkBalance(t, tc, txsel, "A", 0, "600")
  258. checkBalance(t, tc, txsel, "A", 1, "280")
  259. checkBalance(t, tc, txsel, "B", 0, "290")
  260. checkBalance(t, tc, txsel, "B", 1, "200")
  261. checkBalance(t, tc, txsel, "C", 0, "100")
  262. checkBalance(t, tc, txsel, "D", 0, "800")
  263. checkSortedByNonce(t, testAccNonces, oL2Txs)
  264. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs), txsel.localAccountsDB.CurrentBatch())
  265. require.NoError(t, err)
  266. log.Debug("block:0 batch:8")
  267. // simulate the PoolL2Txs of the batch8
  268. batchPoolL2 = `
  269. Type: PoolL2
  270. PoolTransfer(0) A-B: 100 (126)
  271. PoolTransfer(0) C-A: 50 (126)
  272. PoolTransfer(1) B-C: 100 (126)
  273. PoolExit(0) A: 100 (126)`
  274. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  275. require.NoError(t, err)
  276. addL2Txs(t, txsel, poolL2Txs)
  277. // check signatures of L2Txs from the L2DB (to check that the
  278. // parameters of the PoolL2Tx match the original parameters signed
  279. // before inserting it to the L2DB)
  280. l2TxsFromDB, err = txsel.l2db.GetPendingTxs()
  281. require.NoError(t, err)
  282. assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
  283. assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["C"].BJJ.Public().Compress()))
  284. assert.True(t, l2TxsFromDB[2].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
  285. assert.True(t, l2TxsFromDB[3].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
  286. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
  287. coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  288. require.NoError(t, err)
  289. assert.Equal(t, []common.Idx{261, 262}, coordIdxs)
  290. assert.Equal(t, 0, len(accAuths))
  291. assert.Equal(t, 0, len(oL1UserTxs))
  292. assert.Equal(t, 0, len(oL1CoordTxs))
  293. assert.Equal(t, 4, len(oL2Txs))
  294. assert.Equal(t, len(oL1CoordTxs), len(accAuths))
  295. assert.Equal(t, common.BatchNum(8), txsel.localAccountsDB.CurrentBatch())
  296. assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
  297. checkBalanceByIdx(t, txsel, 261, "30")
  298. checkBalanceByIdx(t, txsel, 262, "35")
  299. checkBalance(t, tc, txsel, "A", 0, "430")
  300. checkBalance(t, tc, txsel, "A", 1, "280")
  301. checkBalance(t, tc, txsel, "B", 0, "390")
  302. checkBalance(t, tc, txsel, "B", 1, "90")
  303. checkBalance(t, tc, txsel, "C", 0, "45")
  304. checkBalance(t, tc, txsel, "C", 1, "100")
  305. checkBalance(t, tc, txsel, "D", 0, "800")
  306. checkSortedByNonce(t, testAccNonces, oL2Txs)
  307. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs), txsel.localAccountsDB.CurrentBatch())
  308. require.NoError(t, err)
  309. log.Debug("(batch9)block:1 batch:1")
  310. // simulate the PoolL2Txs of the batch9
  311. batchPoolL2 = `
  312. Type: PoolL2
  313. PoolTransfer(0) D-A: 300 (126)
  314. PoolTransfer(0) B-D: 100 (126)
  315. `
  316. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  317. require.NoError(t, err)
  318. addL2Txs(t, txsel, poolL2Txs)
  319. // check signatures of L2Txs from the L2DB (to check that the
  320. // parameters of the PoolL2Tx match the original parameters signed
  321. // before inserting it to the L2DB)
  322. l2TxsFromDB, err = txsel.l2db.GetPendingTxs()
  323. require.NoError(t, err)
  324. assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["D"].BJJ.Public().Compress()))
  325. assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
  326. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
  327. coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  328. require.NoError(t, err)
  329. assert.Equal(t, []common.Idx{262}, coordIdxs)
  330. assert.Equal(t, 0, len(accAuths))
  331. assert.Equal(t, 4, len(oL1UserTxs))
  332. assert.Equal(t, 0, len(oL1CoordTxs))
  333. assert.Equal(t, 2, len(oL2Txs))
  334. assert.Equal(t, len(oL1CoordTxs), len(accAuths))
  335. assert.Equal(t, common.BatchNum(9), txsel.localAccountsDB.CurrentBatch())
  336. assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
  337. checkBalanceByIdx(t, txsel, 261, "30")
  338. checkBalanceByIdx(t, txsel, 262, "75")
  339. checkBalance(t, tc, txsel, "A", 0, "730")
  340. checkBalance(t, tc, txsel, "A", 1, "280")
  341. checkBalance(t, tc, txsel, "B", 0, "380")
  342. checkBalance(t, tc, txsel, "B", 1, "90")
  343. checkBalance(t, tc, txsel, "C", 0, "845")
  344. checkBalance(t, tc, txsel, "C", 1, "100")
  345. checkBalance(t, tc, txsel, "D", 0, "470")
  346. checkSortedByNonce(t, testAccNonces, oL2Txs)
  347. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs), txsel.localAccountsDB.CurrentBatch())
  348. require.NoError(t, err)
  349. }
  350. func TestPoolL2TxsWithoutEnoughBalance(t *testing.T) {
  351. set := `
  352. Type: Blockchain
  353. CreateAccountDeposit(0) Coord: 0
  354. CreateAccountDeposit(0) A: 100
  355. CreateAccountDeposit(0) B: 100
  356. > batchL1 // freeze L1User{1}
  357. > batchL1 // forge L1User{1}
  358. > block
  359. `
  360. chainID := uint16(0)
  361. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  362. // generate test transactions, the L1CoordinatorTxs generated by Til
  363. // will be ignored at this test, as will be the TxSelector who
  364. // generates them when needed
  365. blocks, err := tc.GenerateBlocks(set)
  366. assert.NoError(t, err)
  367. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  368. txsel := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  369. // restart nonces of TilContext, as will be set by generating directly
  370. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  371. tc.RestartNonces()
  372. tpc := txprocessor.Config{
  373. NLevels: 16,
  374. MaxFeeTx: 10,
  375. MaxTx: 20,
  376. MaxL1Tx: 10,
  377. ChainID: chainID,
  378. }
  379. selectionConfig := &SelectionConfig{
  380. MaxL1UserTxs: 5,
  381. TxProcessorConfig: tpc,
  382. }
  383. // batch1
  384. l1UserTxs := []common.L1Tx{}
  385. _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  386. require.NoError(t, err)
  387. expectedTxID0 := "0x028847b86613c0b70be18c8622119ed045b42e4e47d7938fa90bb3d1dc14928965" // 1st TransferToEthAddr
  388. expectedTxID1 := "0x0200b18773dcf56f770d65870fb02041cb59a088fd35b7c3f3df69f8a250b99a42" // 1st Exit
  389. expectedTxID2 := "0x029720ff506153f970f120ac638cd7ee759eeff2c2012e7634a78e4fdc05c04a90" // 2nd TransferToEthAddr
  390. // batch2
  391. // prepare the PoolL2Txs
  392. batchPoolL2 := `
  393. Type: PoolL2
  394. PoolTransferToEthAddr(0) A-B: 100 (126)
  395. PoolExit(0) B: 100 (126)`
  396. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  397. require.NoError(t, err)
  398. // add the PoolL2Txs to the l2DB
  399. addL2Txs(t, txsel, poolL2Txs)
  400. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  401. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  402. require.NoError(t, err)
  403. assert.Equal(t, 3, len(oL1UserTxs))
  404. assert.Equal(t, 0, len(oL1CoordTxs))
  405. assert.Equal(t, 0, len(oL2Txs)) // should be 0 as the 2 PoolL2Txs does not have enough funds
  406. assert.Equal(t, 2, len(discardedL2Txs))
  407. assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
  408. assert.Equal(t, expectedTxID1, discardedL2Txs[1].TxID.String())
  409. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
  410. require.NoError(t, err)
  411. // as the PoolL2Txs have not been really processed, restart nonces
  412. tc.RestartNonces()
  413. // batch3
  414. // NOTE: this batch will result with 1 L2Tx, as the PoolExit tx is not
  415. // possible, as the PoolTransferToEthAddr is not processed yet when
  416. // checking availability of PoolExit. This, in a near-future iteration
  417. // of the TxSelector will return the 2 transactions as valid and
  418. // selected, as the TxSelector will handle this kind of combinations.
  419. batchPoolL2 = `
  420. Type: PoolL2
  421. PoolTransferToEthAddr(0) A-B: 50 (126)`
  422. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  423. require.NoError(t, err)
  424. addL2Txs(t, txsel, poolL2Txs)
  425. l1UserTxs = []common.L1Tx{}
  426. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  427. require.NoError(t, err)
  428. assert.Equal(t, 0, len(oL1UserTxs))
  429. assert.Equal(t, 0, len(oL1CoordTxs))
  430. assert.Equal(t, 1, len(oL2Txs)) // see 'NOTE' at the beginning of 'batch3' of this test
  431. assert.Equal(t, 2, len(discardedL2Txs))
  432. assert.Equal(t, expectedTxID2, oL2Txs[0].TxID.String())
  433. assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
  434. assert.Equal(t, expectedTxID1, discardedL2Txs[1].TxID.String())
  435. assert.Equal(t, common.TxTypeTransferToEthAddr, oL2Txs[0].Type)
  436. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
  437. require.NoError(t, err)
  438. // batch4
  439. // make the selection of another batch, which should include the
  440. // initial PoolExit, which now is valid as B has enough Balance
  441. l1UserTxs = []common.L1Tx{}
  442. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  443. require.NoError(t, err)
  444. assert.Equal(t, 0, len(oL1UserTxs))
  445. assert.Equal(t, 0, len(oL1CoordTxs))
  446. assert.Equal(t, 1, len(oL2Txs))
  447. assert.Equal(t, 1, len(discardedL2Txs))
  448. assert.Equal(t, expectedTxID1, oL2Txs[0].TxID.String()) // the Exit that was not accepted at the batch2
  449. assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
  450. assert.Equal(t, common.TxTypeExit, oL2Txs[0].Type)
  451. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
  452. require.NoError(t, err)
  453. }
  454. func TestTransferToBjj(t *testing.T) {
  455. set := `
  456. Type: Blockchain
  457. AddToken(1)
  458. CreateAccountDeposit(0) Coord: 0
  459. CreateAccountDeposit(0) A: 1000
  460. CreateAccountDeposit(0) B: 1000
  461. CreateAccountDeposit(1) B: 1000
  462. > batchL1 // freeze L1User{1}
  463. > batchL1 // forge L1User{1}
  464. > block
  465. `
  466. chainID := uint16(0)
  467. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  468. blocks, err := tc.GenerateBlocks(set)
  469. assert.NoError(t, err)
  470. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  471. txsel := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  472. // restart nonces of TilContext, as will be set by generating directly
  473. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  474. tc.RestartNonces()
  475. addTokens(t, tc, txsel.l2db.DB())
  476. tpc := txprocessor.Config{
  477. NLevels: 16,
  478. MaxFeeTx: 10,
  479. MaxTx: 20,
  480. MaxL1Tx: 10,
  481. ChainID: chainID,
  482. }
  483. selectionConfig := &SelectionConfig{
  484. MaxL1UserTxs: 5,
  485. TxProcessorConfig: tpc,
  486. }
  487. // batch1 to create some accounts with positive balance
  488. l1UserTxs := []common.L1Tx{}
  489. _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  490. require.NoError(t, err)
  491. // Transfer is ToBJJ to a BJJ-only account that doesn't exist
  492. // and the coordinator will create it via L1CoordTx.
  493. batchPoolL2 := `
  494. Type: PoolL2
  495. PoolTransferToBJJ(0) A-B: 50 (126)
  496. `
  497. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  498. require.NoError(t, err)
  499. // add the PoolL2Txs to the l2DB
  500. addL2Txs(t, txsel, poolL2Txs)
  501. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  502. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  503. require.NoError(t, err)
  504. assert.Equal(t, 4, len(oL1UserTxs))
  505. // We expect the coordinator to add an L1CoordTx to create an account for the recipient of the l2tx
  506. require.Equal(t, 1, len(oL1CoordTxs))
  507. assert.Equal(t, poolL2Txs[0].ToEthAddr, oL1CoordTxs[0].FromEthAddr)
  508. assert.Equal(t, poolL2Txs[0].ToBJJ, oL1CoordTxs[0].FromBJJ)
  509. // fmt.Printf("DBG l1CoordTx[0]: %+v\n", oL1CoordTxs[0])
  510. assert.Equal(t, 1, len(oL2Txs))
  511. assert.Equal(t, 0, len(discardedL2Txs))
  512. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
  513. require.NoError(t, err)
  514. // Now the BJJ-only account for B is already created, so the transfer
  515. // happens without an L1CoordTx that creates the user account.
  516. batchPoolL2 = `
  517. Type: PoolL2
  518. PoolTransferToBJJ(0) A-B: 50 (126)
  519. `
  520. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  521. require.NoError(t, err)
  522. addL2Txs(t, txsel, poolL2Txs)
  523. l1UserTxs = []common.L1Tx{}
  524. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  525. require.NoError(t, err)
  526. assert.Equal(t, 0, len(oL1UserTxs))
  527. // Since the BJJ-only account B already exists, the coordinator doesn't add any L1CoordTxs
  528. assert.Equal(t, 0, len(oL1CoordTxs))
  529. assert.Equal(t, 1, len(oL2Txs))
  530. assert.Equal(t, 0, len(discardedL2Txs))
  531. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
  532. require.NoError(t, err)
  533. // The transfer now is ToBJJ to a BJJ-only account that doesn't exist
  534. // and the coordinator will create it via L1CoordTx. Since it's a
  535. // transfer of a token for which the coordinator doesn't have a fee
  536. // account, another L1CoordTx will be created for the coordinator to
  537. // receive the fees.
  538. batchPoolL2 = `
  539. Type: PoolL2
  540. PoolTransferToBJJ(1) B-A: 50 (126)
  541. `
  542. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  543. require.NoError(t, err)
  544. addL2Txs(t, txsel, poolL2Txs)
  545. l1UserTxs = []common.L1Tx{}
  546. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  547. require.NoError(t, err)
  548. assert.Equal(t, 0, len(oL1UserTxs))
  549. // We expect the coordinator to add an L1CoordTx to create an account
  550. // to receive the fees by the coordinator and another one for the
  551. // recipient of the l2tx
  552. assert.Equal(t, 2, len(oL1CoordTxs))
  553. // [0] Coordinator account cration for token 1
  554. assert.Equal(t, tc.Users["Coord"].Addr, oL1CoordTxs[0].FromEthAddr)
  555. // [1] User A BJJ-only account creation for token 1
  556. assert.Equal(t, poolL2Txs[0].ToEthAddr, oL1CoordTxs[1].FromEthAddr)
  557. assert.Equal(t, poolL2Txs[0].ToBJJ, oL1CoordTxs[1].FromBJJ)
  558. assert.Equal(t, common.TokenID(1), oL1CoordTxs[1].TokenID)
  559. assert.Equal(t, 1, len(oL2Txs))
  560. assert.Equal(t, 0, len(discardedL2Txs))
  561. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
  562. require.NoError(t, err)
  563. }