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.

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