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.

1170 lines
40 KiB

  1. package txprocessor
  2. import (
  3. "io/ioutil"
  4. "math/big"
  5. "os"
  6. "sort"
  7. "testing"
  8. ethCommon "github.com/ethereum/go-ethereum/common"
  9. "github.com/hermeznetwork/hermez-node/common"
  10. "github.com/hermeznetwork/hermez-node/db/statedb"
  11. "github.com/hermeznetwork/hermez-node/log"
  12. "github.com/hermeznetwork/hermez-node/test/til"
  13. "github.com/hermeznetwork/hermez-node/test/txsets"
  14. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. )
  17. func checkBalance(t *testing.T, tc *til.Context, sdb *statedb.StateDB, username string, tokenid int, expected string) {
  18. idx := tc.Users[username].Accounts[common.TokenID(tokenid)].Idx
  19. acc, err := sdb.GetAccount(idx)
  20. require.NoError(t, err)
  21. assert.Equal(t, expected, acc.Balance.String())
  22. }
  23. func checkBalanceByIdx(t *testing.T, sdb *statedb.StateDB, idx common.Idx, expected string) {
  24. acc, err := sdb.GetAccount(idx)
  25. require.NoError(t, err)
  26. assert.Equal(t, expected, acc.Balance.String())
  27. }
  28. func TestComputeEffectiveAmounts(t *testing.T) {
  29. dir, err := ioutil.TempDir("", "tmpdb")
  30. require.NoError(t, err)
  31. defer assert.NoError(t, os.RemoveAll(dir))
  32. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  33. Type: statedb.TypeSynchronizer, NLevels: 32})
  34. assert.NoError(t, err)
  35. set := `
  36. Type: Blockchain
  37. AddToken(1)
  38. CreateAccountDeposit(0) A: 10
  39. CreateAccountDeposit(0) B: 10
  40. CreateAccountDeposit(1) C: 10
  41. > batchL1
  42. > batchL1
  43. > block
  44. `
  45. chainID := uint16(0)
  46. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  47. blocks, err := tc.GenerateBlocks(set)
  48. require.NoError(t, err)
  49. config := Config{
  50. NLevels: 32,
  51. MaxFeeTx: 64,
  52. MaxTx: 512,
  53. MaxL1Tx: 16,
  54. ChainID: chainID,
  55. }
  56. tp := NewTxProcessor(sdb, config)
  57. _, err = tp.ProcessTxs(nil, blocks[0].Rollup.L1UserTxs, nil, nil)
  58. require.NoError(t, err)
  59. tx := common.L1Tx{
  60. FromIdx: 256,
  61. ToIdx: 257,
  62. Amount: big.NewInt(10),
  63. DepositAmount: big.NewInt(0),
  64. FromEthAddr: tc.Users["A"].Addr,
  65. UserOrigin: true,
  66. }
  67. tp.computeEffectiveAmounts(&tx)
  68. assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  69. assert.Equal(t, big.NewInt(10), tx.EffectiveAmount)
  70. // expect error due not enough funds
  71. tx = common.L1Tx{
  72. FromIdx: 256,
  73. ToIdx: 257,
  74. Amount: big.NewInt(11),
  75. DepositAmount: big.NewInt(0),
  76. FromEthAddr: tc.Users["A"].Addr,
  77. UserOrigin: true,
  78. }
  79. tp.computeEffectiveAmounts(&tx)
  80. assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  81. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  82. // expect no-error as there are enough funds in a
  83. // CreateAccountDepositTransfer transction
  84. tx = common.L1Tx{
  85. FromIdx: 0,
  86. ToIdx: 257,
  87. Amount: big.NewInt(10),
  88. DepositAmount: big.NewInt(10),
  89. UserOrigin: true,
  90. }
  91. tp.computeEffectiveAmounts(&tx)
  92. assert.Equal(t, big.NewInt(10), tx.EffectiveDepositAmount)
  93. assert.Equal(t, big.NewInt(10), tx.EffectiveAmount)
  94. // expect error due not enough funds in a CreateAccountDepositTransfer
  95. // transction
  96. tx = common.L1Tx{
  97. FromIdx: 0,
  98. ToIdx: 257,
  99. Amount: big.NewInt(11),
  100. DepositAmount: big.NewInt(10),
  101. UserOrigin: true,
  102. }
  103. tp.computeEffectiveAmounts(&tx)
  104. assert.Equal(t, big.NewInt(10), tx.EffectiveDepositAmount)
  105. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  106. // expect error due not same TokenID
  107. tx = common.L1Tx{
  108. FromIdx: 256,
  109. ToIdx: 258,
  110. Amount: big.NewInt(5),
  111. DepositAmount: big.NewInt(0),
  112. FromEthAddr: tc.Users["A"].Addr,
  113. UserOrigin: true,
  114. }
  115. tp.computeEffectiveAmounts(&tx)
  116. assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  117. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  118. // expect error due not same EthAddr
  119. tx = common.L1Tx{
  120. FromIdx: 256,
  121. ToIdx: 257,
  122. Amount: big.NewInt(8),
  123. DepositAmount: big.NewInt(0),
  124. FromEthAddr: tc.Users["B"].Addr,
  125. UserOrigin: true,
  126. }
  127. tp.computeEffectiveAmounts(&tx)
  128. assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  129. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  130. // expect on TxTypeDepositTransfer EffectiveAmount=0, but
  131. // EffectiveDepositAmount!=0, due not enough funds to make the transfer
  132. tx = common.L1Tx{
  133. FromIdx: 256,
  134. ToIdx: 257,
  135. Amount: big.NewInt(20),
  136. DepositAmount: big.NewInt(8),
  137. FromEthAddr: tc.Users["A"].Addr,
  138. UserOrigin: true,
  139. }
  140. tp.computeEffectiveAmounts(&tx)
  141. assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
  142. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  143. // expect on TxTypeDepositTransfer EffectiveAmount=0, but
  144. // EffectiveDepositAmount!=0, due different EthAddr from FromIdx
  145. // address
  146. tx = common.L1Tx{
  147. FromIdx: 256,
  148. ToIdx: 257,
  149. Amount: big.NewInt(8),
  150. DepositAmount: big.NewInt(8),
  151. FromEthAddr: tc.Users["B"].Addr,
  152. UserOrigin: true,
  153. }
  154. tp.computeEffectiveAmounts(&tx)
  155. assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
  156. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  157. // CreateAccountDepositTransfer for TokenID=1 when receiver does not
  158. // have an account for that TokenID, expect that the
  159. // EffectiveDepositAmount=DepositAmount, but EffectiveAmount==0
  160. tx = common.L1Tx{
  161. FromIdx: 0,
  162. ToIdx: 257,
  163. Amount: big.NewInt(8),
  164. DepositAmount: big.NewInt(8),
  165. FromEthAddr: tc.Users["A"].Addr,
  166. TokenID: 2,
  167. UserOrigin: true,
  168. Type: common.TxTypeCreateAccountDepositTransfer,
  169. }
  170. tp.computeEffectiveAmounts(&tx)
  171. assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
  172. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  173. // DepositTransfer for TokenID=1 when receiver does not have an account
  174. // for that TokenID, expect that the
  175. // EffectiveDepositAmount=DepositAmount, but EffectiveAmount=0
  176. tx = common.L1Tx{
  177. FromIdx: 258,
  178. ToIdx: 256,
  179. Amount: big.NewInt(8),
  180. DepositAmount: big.NewInt(8),
  181. FromEthAddr: tc.Users["C"].Addr,
  182. TokenID: 1,
  183. UserOrigin: true,
  184. Type: common.TxTypeDepositTransfer,
  185. }
  186. tp.computeEffectiveAmounts(&tx)
  187. assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
  188. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  189. }
  190. func TestProcessTxsBalances(t *testing.T) {
  191. dir, err := ioutil.TempDir("", "tmpdb")
  192. require.NoError(t, err)
  193. defer assert.NoError(t, os.RemoveAll(dir))
  194. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  195. Type: statedb.TypeSynchronizer, NLevels: 32})
  196. assert.NoError(t, err)
  197. chainID := uint16(0)
  198. // generate test transactions from test.SetBlockchain0 code
  199. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  200. blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
  201. require.NoError(t, err)
  202. config := Config{
  203. NLevels: 32,
  204. MaxFeeTx: 64,
  205. MaxTx: 512,
  206. MaxL1Tx: 16,
  207. ChainID: chainID,
  208. }
  209. tp := NewTxProcessor(sdb, config)
  210. log.Debug("block:0 batch:1, only L1CoordinatorTxs")
  211. _, err = tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
  212. require.NoError(t, err)
  213. assert.Equal(t, "0", tp.s.MT.Root().BigInt().String())
  214. log.Debug("block:0 batch:2")
  215. l1UserTxs := []common.L1Tx{}
  216. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  217. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  218. require.NoError(t, err)
  219. assert.Equal(t, "0", tp.s.MT.Root().BigInt().String())
  220. log.Debug("block:0 batch:3")
  221. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
  222. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
  223. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
  224. require.NoError(t, err)
  225. checkBalance(t, tc, sdb, "A", 0, "500")
  226. assert.Equal(t, "13644148972047617726265275926674266298636745191961029124811988256139761111521", tp.s.MT.Root().BigInt().String())
  227. log.Debug("block:0 batch:4")
  228. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
  229. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[3].L2Txs)
  230. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[3].L1CoordinatorTxs, l2Txs)
  231. require.NoError(t, err)
  232. checkBalance(t, tc, sdb, "A", 0, "500")
  233. checkBalance(t, tc, sdb, "A", 1, "500")
  234. assert.Equal(t, "12433441613247342495680642890662773367605896324555599297255745922589338651261", tp.s.MT.Root().BigInt().String())
  235. log.Debug("block:0 batch:5")
  236. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
  237. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[4].L2Txs)
  238. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[4].L1CoordinatorTxs, l2Txs)
  239. require.NoError(t, err)
  240. checkBalance(t, tc, sdb, "A", 0, "500")
  241. checkBalance(t, tc, sdb, "A", 1, "500")
  242. assert.Equal(t, "12433441613247342495680642890662773367605896324555599297255745922589338651261", tp.s.MT.Root().BigInt().String())
  243. log.Debug("block:0 batch:6")
  244. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
  245. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[5].L2Txs)
  246. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[5].L1CoordinatorTxs, l2Txs)
  247. require.NoError(t, err)
  248. checkBalance(t, tc, sdb, "A", 0, "600")
  249. checkBalance(t, tc, sdb, "A", 1, "500")
  250. checkBalance(t, tc, sdb, "B", 0, "400")
  251. assert.Equal(t, "4191361650490017591061467288209836928064232431729236465872209988325272262963", tp.s.MT.Root().BigInt().String())
  252. coordIdxs := []common.Idx{261, 262}
  253. log.Debug("block:0 batch:7")
  254. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
  255. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[6].L2Txs)
  256. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[6].L1CoordinatorTxs, l2Txs)
  257. require.NoError(t, err)
  258. checkBalance(t, tc, sdb, "Coord", 0, "10")
  259. checkBalance(t, tc, sdb, "Coord", 1, "20")
  260. checkBalance(t, tc, sdb, "A", 0, "600")
  261. checkBalance(t, tc, sdb, "A", 1, "280")
  262. checkBalance(t, tc, sdb, "B", 0, "290")
  263. checkBalance(t, tc, sdb, "B", 1, "200")
  264. checkBalance(t, tc, sdb, "C", 0, "100")
  265. checkBalance(t, tc, sdb, "D", 0, "800")
  266. assert.Equal(t, "7614010373759339299470010949167613050707822522530721724565424494781010548240", tp.s.MT.Root().BigInt().String())
  267. log.Debug("block:0 batch:8")
  268. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
  269. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[7].L2Txs)
  270. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[7].L1CoordinatorTxs, l2Txs)
  271. require.NoError(t, err)
  272. checkBalance(t, tc, sdb, "Coord", 0, "35")
  273. checkBalance(t, tc, sdb, "Coord", 1, "30")
  274. checkBalance(t, tc, sdb, "A", 0, "430")
  275. checkBalance(t, tc, sdb, "A", 1, "280")
  276. checkBalance(t, tc, sdb, "B", 0, "390")
  277. checkBalance(t, tc, sdb, "B", 1, "90")
  278. checkBalance(t, tc, sdb, "C", 0, "45")
  279. checkBalance(t, tc, sdb, "C", 1, "100")
  280. checkBalance(t, tc, sdb, "D", 0, "800")
  281. assert.Equal(t, "21231789250434471575486264439945776732824482207853465397552873521865656677689", tp.s.MT.Root().BigInt().String())
  282. coordIdxs = []common.Idx{262}
  283. log.Debug("block:1 batch:1")
  284. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
  285. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
  286. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
  287. require.NoError(t, err)
  288. checkBalance(t, tc, sdb, "Coord", 0, "75")
  289. checkBalance(t, tc, sdb, "Coord", 1, "30")
  290. checkBalance(t, tc, sdb, "A", 0, "730")
  291. checkBalance(t, tc, sdb, "A", 1, "280")
  292. checkBalance(t, tc, sdb, "B", 0, "380")
  293. checkBalance(t, tc, sdb, "B", 1, "90")
  294. checkBalance(t, tc, sdb, "C", 0, "845")
  295. checkBalance(t, tc, sdb, "C", 1, "100")
  296. checkBalance(t, tc, sdb, "D", 0, "470")
  297. assert.Equal(t, "11289313644810782435120113035387729451095637380468777086895109386127538554246", tp.s.MT.Root().BigInt().String())
  298. coordIdxs = []common.Idx{}
  299. log.Debug("block:1 batch:2")
  300. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  301. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
  302. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  303. require.NoError(t, err)
  304. assert.Equal(t, "10342681351319338354912862547249967104198317571995055517008223832276478908482", tp.s.MT.Root().BigInt().String())
  305. // use Set of PoolL2 txs
  306. poolL2Txs, err := tc.GeneratePoolL2Txs(txsets.SetPoolL2MinimumFlow1)
  307. assert.NoError(t, err)
  308. _, err = tp.ProcessTxs(coordIdxs, []common.L1Tx{}, []common.L1Tx{}, poolL2Txs)
  309. require.NoError(t, err)
  310. checkBalance(t, tc, sdb, "Coord", 0, "75")
  311. checkBalance(t, tc, sdb, "Coord", 1, "30")
  312. checkBalance(t, tc, sdb, "A", 0, "510")
  313. checkBalance(t, tc, sdb, "A", 1, "170")
  314. checkBalance(t, tc, sdb, "B", 0, "480")
  315. checkBalance(t, tc, sdb, "B", 1, "190")
  316. checkBalance(t, tc, sdb, "C", 0, "845")
  317. checkBalance(t, tc, sdb, "C", 1, "100")
  318. checkBalance(t, tc, sdb, "D", 0, "360")
  319. checkBalance(t, tc, sdb, "F", 0, "100")
  320. }
  321. func TestProcessTxsSynchronizer(t *testing.T) {
  322. dir, err := ioutil.TempDir("", "tmpdb")
  323. require.NoError(t, err)
  324. defer assert.NoError(t, os.RemoveAll(dir))
  325. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  326. Type: statedb.TypeSynchronizer, NLevels: 32})
  327. assert.NoError(t, err)
  328. chainID := uint16(0)
  329. // generate test transactions from test.SetBlockchain0 code
  330. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  331. blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
  332. require.NoError(t, err)
  333. assert.Equal(t, 31, len(blocks[0].Rollup.L1UserTxs))
  334. assert.Equal(t, 4, len(blocks[0].Rollup.Batches[0].L1CoordinatorTxs))
  335. assert.Equal(t, 0, len(blocks[0].Rollup.Batches[1].L1CoordinatorTxs))
  336. assert.Equal(t, 22, len(blocks[0].Rollup.Batches[2].L2Txs))
  337. assert.Equal(t, 1, len(blocks[1].Rollup.Batches[0].L1CoordinatorTxs))
  338. assert.Equal(t, 62, len(blocks[1].Rollup.Batches[0].L2Txs))
  339. assert.Equal(t, 1, len(blocks[1].Rollup.Batches[1].L1CoordinatorTxs))
  340. assert.Equal(t, 8, len(blocks[1].Rollup.Batches[1].L2Txs))
  341. // Coordinator Idx where to send the fees
  342. coordIdxs := []common.Idx{256, 257, 258, 259}
  343. // Idx of user 'A'
  344. idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
  345. config := Config{
  346. NLevels: 32,
  347. MaxFeeTx: 64,
  348. MaxTx: 512,
  349. MaxL1Tx: 32,
  350. ChainID: chainID,
  351. }
  352. tp := NewTxProcessor(sdb, config)
  353. // Process the 1st batch, which contains the L1CoordinatorTxs necessary
  354. // to create the Coordinator accounts to receive the fees
  355. log.Debug("block:0 batch:1, only L1CoordinatorTxs")
  356. ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
  357. require.NoError(t, err)
  358. assert.Equal(t, 4, len(ptOut.CreatedAccounts))
  359. assert.Equal(t, 0, len(ptOut.CollectedFees))
  360. log.Debug("block:0 batch:2")
  361. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  362. ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs,
  363. blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  364. require.NoError(t, err)
  365. assert.Equal(t, 0, len(ptOut.ExitInfos))
  366. assert.Equal(t, 31, len(ptOut.CreatedAccounts))
  367. assert.Equal(t, 4, len(ptOut.CollectedFees))
  368. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
  369. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
  370. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  371. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  372. acc, err := sdb.GetAccount(idxA1)
  373. require.NoError(t, err)
  374. assert.Equal(t, "50", acc.Balance.String())
  375. log.Debug("block:0 batch:3")
  376. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
  377. ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
  378. require.NoError(t, err)
  379. assert.Equal(t, 0, len(ptOut.ExitInfos))
  380. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  381. assert.Equal(t, 4, len(ptOut.CollectedFees))
  382. assert.Equal(t, "2", ptOut.CollectedFees[common.TokenID(0)].String())
  383. assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
  384. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  385. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  386. acc, err = sdb.GetAccount(idxA1)
  387. require.NoError(t, err)
  388. assert.Equal(t, "35", acc.Balance.String())
  389. log.Debug("block:1 batch:1")
  390. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
  391. // before processing expect l2Txs[0:2].Nonce==0
  392. assert.Equal(t, common.Nonce(0), l2Txs[0].Nonce)
  393. assert.Equal(t, common.Nonce(0), l2Txs[1].Nonce)
  394. assert.Equal(t, common.Nonce(0), l2Txs[2].Nonce)
  395. ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
  396. require.NoError(t, err)
  397. // after processing expect l2Txs[0:2].Nonce!=0 and has expected value
  398. assert.Equal(t, common.Nonce(5), l2Txs[0].Nonce)
  399. assert.Equal(t, common.Nonce(6), l2Txs[1].Nonce)
  400. assert.Equal(t, common.Nonce(7), l2Txs[2].Nonce)
  401. assert.Equal(t, 4, len(ptOut.ExitInfos)) // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs
  402. assert.Equal(t, 1, len(ptOut.CreatedAccounts))
  403. assert.Equal(t, 4, len(ptOut.CollectedFees))
  404. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
  405. assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
  406. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  407. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  408. acc, err = sdb.GetAccount(idxA1)
  409. require.NoError(t, err)
  410. assert.Equal(t, "57", acc.Balance.String())
  411. log.Debug("block:1 batch:2")
  412. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
  413. ptOut, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs,
  414. blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  415. require.NoError(t, err)
  416. assert.Equal(t, 1, len(ptOut.ExitInfos)) // 1, as previous batch was without L1UserTxs, and has pending the 'ForceExit(1) A: 5', and the 2 exit transactions get grouped under 1 ExitInfo
  417. assert.Equal(t, 1, len(ptOut.CreatedAccounts))
  418. assert.Equal(t, 4, len(ptOut.CollectedFees))
  419. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
  420. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
  421. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  422. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  423. acc, err = sdb.GetAccount(idxA1)
  424. assert.NoError(t, err)
  425. assert.Equal(t, "77", acc.Balance.String())
  426. idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
  427. acc, err = sdb.GetAccount(idxB0)
  428. require.NoError(t, err)
  429. assert.Equal(t, "51", acc.Balance.String())
  430. // get balance of Coordinator account for TokenID==0
  431. acc, err = sdb.GetAccount(common.Idx(256))
  432. require.NoError(t, err)
  433. assert.Equal(t, "2", acc.Balance.String())
  434. }
  435. func TestProcessTxsBatchBuilder(t *testing.T) {
  436. dir, err := ioutil.TempDir("", "tmpdb")
  437. require.NoError(t, err)
  438. defer assert.NoError(t, os.RemoveAll(dir))
  439. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  440. Type: statedb.TypeBatchBuilder, NLevels: 32})
  441. assert.NoError(t, err)
  442. chainID := uint16(0)
  443. // generate test transactions from test.SetBlockchain0 code
  444. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  445. blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
  446. require.NoError(t, err)
  447. // Coordinator Idx where to send the fees
  448. coordIdxs := []common.Idx{256, 257, 258, 259}
  449. // Idx of user 'A'
  450. idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
  451. config := Config{
  452. NLevels: 32,
  453. MaxFeeTx: 64,
  454. MaxTx: 512,
  455. MaxL1Tx: 32,
  456. ChainID: chainID,
  457. }
  458. tp := NewTxProcessor(sdb, config)
  459. // Process the 1st batch, which contains the L1CoordinatorTxs necessary
  460. // to create the Coordinator accounts to receive the fees
  461. log.Debug("block:0 batch:1, only L1CoordinatorTxs")
  462. ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
  463. require.NoError(t, err)
  464. // expect 0 at CreatedAccount, as is only computed when StateDB.Type==TypeSynchronizer
  465. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  466. log.Debug("block:0 batch:2")
  467. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  468. ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  469. require.NoError(t, err)
  470. assert.Equal(t, 0, len(ptOut.ExitInfos))
  471. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  472. acc, err := sdb.GetAccount(idxA1)
  473. require.NoError(t, err)
  474. assert.Equal(t, "50", acc.Balance.String())
  475. log.Debug("block:0 batch:3")
  476. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
  477. ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
  478. require.NoError(t, err)
  479. assert.Equal(t, 0, len(ptOut.ExitInfos))
  480. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  481. acc, err = sdb.GetAccount(idxA1)
  482. require.NoError(t, err)
  483. assert.Equal(t, "35", acc.Balance.String())
  484. log.Debug("block:1 batch:1")
  485. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
  486. _, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
  487. require.NoError(t, err)
  488. acc, err = sdb.GetAccount(idxA1)
  489. require.NoError(t, err)
  490. assert.Equal(t, "57", acc.Balance.String())
  491. log.Debug("block:1 batch:2")
  492. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
  493. _, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  494. require.NoError(t, err)
  495. acc, err = sdb.GetAccount(idxA1)
  496. assert.NoError(t, err)
  497. assert.Equal(t, "77", acc.Balance.String())
  498. idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
  499. acc, err = sdb.GetAccount(idxB0)
  500. require.NoError(t, err)
  501. assert.Equal(t, "51", acc.Balance.String())
  502. // get balance of Coordinator account for TokenID==0
  503. acc, err = sdb.GetAccount(common.Idx(256))
  504. require.NoError(t, err)
  505. assert.Equal(t, common.TokenID(0), acc.TokenID)
  506. assert.Equal(t, "2", acc.Balance.String())
  507. acc, err = sdb.GetAccount(common.Idx(257))
  508. require.NoError(t, err)
  509. assert.Equal(t, common.TokenID(1), acc.TokenID)
  510. assert.Equal(t, "2", acc.Balance.String())
  511. assert.Equal(t, "18894163991492573893706613133132363559300580460789469708968288074813925659539", sdb.MT.Root().BigInt().String())
  512. }
  513. func TestProcessTxsRootTestVectors(t *testing.T) {
  514. dir, err := ioutil.TempDir("", "tmpdb")
  515. require.NoError(t, err)
  516. defer assert.NoError(t, os.RemoveAll(dir))
  517. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  518. Type: statedb.TypeBatchBuilder, NLevels: 32})
  519. assert.NoError(t, err)
  520. // same values than in the js test
  521. bjj0, err := common.BJJFromStringWithChecksum("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7")
  522. assert.NoError(t, err)
  523. l1Txs := []common.L1Tx{
  524. {
  525. FromIdx: 0,
  526. DepositAmount: big.NewInt(16000000),
  527. Amount: big.NewInt(0),
  528. TokenID: 1,
  529. FromBJJ: bjj0,
  530. FromEthAddr: ethCommon.HexToAddress("0x7e5f4552091a69125d5dfcb7b8c2659029395bdf"),
  531. ToIdx: 0,
  532. Type: common.TxTypeCreateAccountDeposit,
  533. UserOrigin: true,
  534. },
  535. }
  536. l2Txs := []common.PoolL2Tx{
  537. {
  538. FromIdx: 256,
  539. ToIdx: 256,
  540. TokenID: 1,
  541. Amount: big.NewInt(1000),
  542. Nonce: 0,
  543. Fee: 126,
  544. Type: common.TxTypeTransfer,
  545. },
  546. }
  547. chainID := uint16(0)
  548. config := Config{
  549. NLevels: 32,
  550. MaxFeeTx: 8,
  551. MaxTx: 32,
  552. MaxL1Tx: 16,
  553. ChainID: chainID,
  554. }
  555. tp := NewTxProcessor(sdb, config)
  556. _, err = tp.ProcessTxs(nil, l1Txs, nil, l2Txs)
  557. require.NoError(t, err)
  558. assert.Equal(t, "9827704113668630072730115158977131501210702363656902211840117643154933433410", sdb.MT.Root().BigInt().String())
  559. }
  560. func TestCreateAccountDepositMaxValue(t *testing.T) {
  561. dir, err := ioutil.TempDir("", "tmpdb")
  562. require.NoError(t, err)
  563. defer assert.NoError(t, os.RemoveAll(dir))
  564. nLevels := 16
  565. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  566. Type: statedb.TypeBatchBuilder, NLevels: nLevels})
  567. assert.NoError(t, err)
  568. users := txsets.GenerateJsUsers(t)
  569. daMaxF40 := common.Float40(0xFFFFFFFFFF)
  570. daMaxBI, err := daMaxF40.BigInt()
  571. require.NoError(t, err)
  572. assert.Equal(t, "343597383670000000000000000000000000000000", daMaxBI.String())
  573. daMax1F40 := common.Float40(0xFFFFFFFFFE)
  574. require.NoError(t, err)
  575. daMax1BI, err := daMax1F40.BigInt()
  576. require.NoError(t, err)
  577. assert.Equal(t, "343597383660000000000000000000000000000000", daMax1BI.String())
  578. l1Txs := []common.L1Tx{
  579. {
  580. FromIdx: 0,
  581. DepositAmount: daMaxBI,
  582. Amount: big.NewInt(0),
  583. TokenID: 1,
  584. FromBJJ: users[0].BJJ.Public().Compress(),
  585. FromEthAddr: users[0].Addr,
  586. ToIdx: 0,
  587. Type: common.TxTypeCreateAccountDeposit,
  588. UserOrigin: true,
  589. },
  590. {
  591. FromIdx: 0,
  592. DepositAmount: daMax1BI,
  593. Amount: big.NewInt(0),
  594. TokenID: 1,
  595. FromBJJ: users[1].BJJ.Public().Compress(),
  596. FromEthAddr: users[1].Addr,
  597. ToIdx: 0,
  598. Type: common.TxTypeCreateAccountDeposit,
  599. UserOrigin: true,
  600. },
  601. }
  602. chainID := uint16(0)
  603. config := Config{
  604. NLevels: uint32(nLevels),
  605. MaxTx: 3,
  606. MaxL1Tx: 2,
  607. MaxFeeTx: 2,
  608. ChainID: chainID,
  609. }
  610. tp := NewTxProcessor(sdb, config)
  611. _, err = tp.ProcessTxs(nil, l1Txs, nil, nil)
  612. require.NoError(t, err)
  613. // check balances
  614. acc, err := sdb.GetAccount(common.Idx(256))
  615. require.NoError(t, err)
  616. assert.Equal(t, daMaxBI, acc.Balance)
  617. acc, err = sdb.GetAccount(common.Idx(257))
  618. require.NoError(t, err)
  619. assert.Equal(t, daMax1BI, acc.Balance)
  620. }
  621. func initTestMultipleCoordIdxForTokenID(t *testing.T) (*TxProcessor, *til.Context, []common.BlockData) {
  622. dir, err := ioutil.TempDir("", "tmpdb")
  623. require.NoError(t, err)
  624. defer assert.NoError(t, os.RemoveAll(dir))
  625. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  626. Type: statedb.TypeBatchBuilder, NLevels: 32})
  627. assert.NoError(t, err)
  628. chainID := uint16(1)
  629. // generate test transactions from test.SetBlockchain0 code
  630. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  631. set := `
  632. Type: Blockchain
  633. CreateAccountDeposit(0) A: 200
  634. > batchL1 // freeze L1User{1}
  635. CreateAccountCoordinator(0) Coord
  636. CreateAccountCoordinator(0) B
  637. Transfer(0) A-B: 100 (126)
  638. > batchL1 // forge L1User{1}, forge L1Coord{4}, forge L2{2}
  639. > block
  640. `
  641. blocks, err := tc.GenerateBlocks(set)
  642. require.NoError(t, err)
  643. config := Config{
  644. NLevels: 32,
  645. MaxFeeTx: 64,
  646. MaxTx: 512,
  647. MaxL1Tx: 16,
  648. ChainID: chainID,
  649. }
  650. tp := NewTxProcessor(sdb, config)
  651. // batch1
  652. _, err = tp.ProcessTxs(nil, nil, nil, nil) // to simulate the first batch from the Til set
  653. require.NoError(t, err)
  654. return tp, tc, blocks
  655. }
  656. func TestMultipleCoordIdxForTokenID(t *testing.T) {
  657. // Check that ProcessTxs always uses the first occurrence of the
  658. // CoordIdx for each TokenID
  659. coordIdxs := []common.Idx{257, 257, 257}
  660. tp, tc, blocks := initTestMultipleCoordIdxForTokenID(t)
  661. l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  662. l1CoordTxs := blocks[0].Rollup.Batches[1].L1CoordinatorTxs
  663. l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
  664. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  665. _, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
  666. require.NoError(t, err)
  667. checkBalanceByIdx(t, tp.s, 256, "90") // A
  668. checkBalanceByIdx(t, tp.s, 257, "10") // Coord0
  669. checkBalanceByIdx(t, tp.s, 258, "100") // B
  670. checkBalanceByIdx(t, tp.s, 259, "0") // Coord0
  671. // reset StateDB values
  672. coordIdxs = []common.Idx{259, 257}
  673. tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
  674. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  675. l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
  676. l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
  677. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  678. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
  679. require.NoError(t, err)
  680. checkBalanceByIdx(t, tp.s, 256, "90") // A
  681. checkBalanceByIdx(t, tp.s, 257, "0") // Coord0
  682. checkBalanceByIdx(t, tp.s, 258, "100") // B
  683. checkBalanceByIdx(t, tp.s, 259, "10") // Coord0
  684. // reset StateDB values
  685. coordIdxs = []common.Idx{257, 259}
  686. tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
  687. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  688. l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
  689. l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
  690. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  691. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
  692. require.NoError(t, err)
  693. checkBalanceByIdx(t, tp.s, 256, "90") // A
  694. checkBalanceByIdx(t, tp.s, 257, "10") // Coord0
  695. checkBalanceByIdx(t, tp.s, 258, "100") // B
  696. checkBalanceByIdx(t, tp.s, 259, "0") // Coord0
  697. }
  698. func testTwoExits(t *testing.T, stateDBType statedb.TypeStateDB) ([]*ProcessTxOutput,
  699. []*ProcessTxOutput, []*ProcessTxOutput) {
  700. // In the first part we generate a batch with two force exits for the
  701. // same account of 20 each. The txprocessor output should be a single
  702. // exitInfo with balance of 40.
  703. dir, err := ioutil.TempDir("", "tmpdb")
  704. require.NoError(t, err)
  705. defer assert.NoError(t, os.RemoveAll(dir))
  706. nLevels := 16
  707. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  708. Type: stateDBType, NLevels: nLevels})
  709. assert.NoError(t, err)
  710. chainID := uint16(1)
  711. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  712. // Two exits for the same account. The tx processor should output a
  713. // single exit with the accumulated exit balance
  714. set := `
  715. Type: Blockchain
  716. CreateAccountDeposit(0) A: 100
  717. > batchL1 // freeze L1User{1}
  718. > batchL1 // forge L1User{1}
  719. ForceExit(0) A: 20
  720. ForceExit(0) A: 20
  721. > batchL1 // freeze L1User{2}
  722. > batchL1 // forge L1User{2}
  723. > block
  724. `
  725. blocks, err := tc.GenerateBlocks(set)
  726. require.NoError(t, err)
  727. err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
  728. require.NoError(t, err)
  729. err = tc.FillBlocksForgedL1UserTxs(blocks)
  730. require.NoError(t, err)
  731. // Sanity check
  732. require.Equal(t, 1, len(blocks[0].Rollup.Batches[1].L1UserTxs))
  733. require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
  734. config := Config{
  735. NLevels: uint32(nLevels),
  736. MaxTx: 3,
  737. MaxL1Tx: 2,
  738. MaxFeeTx: 2,
  739. ChainID: chainID,
  740. }
  741. tp := NewTxProcessor(sdb, config)
  742. ptOuts := []*ProcessTxOutput{}
  743. for _, block := range blocks {
  744. for _, batch := range block.Rollup.Batches {
  745. ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
  746. require.NoError(t, err)
  747. ptOuts = append(ptOuts, ptOut)
  748. }
  749. }
  750. acc, err := sdb.GetAccount(256)
  751. require.NoError(t, err)
  752. assert.Equal(t, big.NewInt(60), acc.Balance)
  753. // In the second part we start a fresh statedb and generate a batch
  754. // with one force exit for the same account as before. The txprocessor
  755. // output should be a single exitInfo with balance of 40, and the exit
  756. // merkle tree proof should be equal to the previous one.
  757. dir2, err := ioutil.TempDir("", "tmpdb")
  758. require.NoError(t, err)
  759. defer assert.NoError(t, os.RemoveAll(dir2))
  760. sdb2, err := statedb.NewStateDB(statedb.Config{Path: dir2, Keep: 128,
  761. Type: stateDBType, NLevels: nLevels})
  762. assert.NoError(t, err)
  763. tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  764. // Single exit with balance of both exits in previous set. The exit
  765. // root should match.
  766. set2 := `
  767. Type: Blockchain
  768. CreateAccountDeposit(0) A: 100
  769. > batchL1 // freeze L1User{1}
  770. > batchL1 // forge L1User{1}
  771. ForceExit(0) A: 40
  772. > batchL1 // freeze L1User{2}
  773. > batchL1 // forge L1User{2}
  774. > block
  775. `
  776. blocks, err = tc.GenerateBlocks(set2)
  777. require.NoError(t, err)
  778. err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
  779. require.NoError(t, err)
  780. err = tc.FillBlocksForgedL1UserTxs(blocks)
  781. require.NoError(t, err)
  782. tp = NewTxProcessor(sdb2, config)
  783. ptOuts2 := []*ProcessTxOutput{}
  784. for _, block := range blocks {
  785. for _, batch := range block.Rollup.Batches {
  786. ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
  787. require.NoError(t, err)
  788. ptOuts2 = append(ptOuts2, ptOut)
  789. }
  790. }
  791. // In the third part we start a fresh statedb and generate a batch with
  792. // two force exit for the same account as before but where the 1st Exit
  793. // is with all the amount, and the 2nd Exit is with more amount than
  794. // the available balance. The txprocessor output should be a single
  795. // exitInfo with balance of 40, and the exit merkle tree proof should
  796. // be equal to the previous ones.
  797. dir3, err := ioutil.TempDir("", "tmpdb")
  798. require.NoError(t, err)
  799. defer assert.NoError(t, os.RemoveAll(dir3))
  800. sdb3, err := statedb.NewStateDB(statedb.Config{Path: dir3, Keep: 128,
  801. Type: stateDBType, NLevels: nLevels})
  802. assert.NoError(t, err)
  803. tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  804. // Single exit with balance of both exits in previous set. The exit
  805. // root should match.
  806. set3 := `
  807. Type: Blockchain
  808. CreateAccountDeposit(0) A: 100
  809. > batchL1 // freeze L1User{1}
  810. > batchL1 // forge L1User{1}
  811. ForceExit(0) A: 40
  812. ForceExit(0) A: 100
  813. > batchL1 // freeze L1User{2}
  814. > batchL1 // forge L1User{2}
  815. > block
  816. `
  817. blocks, err = tc.GenerateBlocks(set3)
  818. require.NoError(t, err)
  819. err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
  820. require.NoError(t, err)
  821. err = tc.FillBlocksForgedL1UserTxs(blocks)
  822. require.NoError(t, err)
  823. tp = NewTxProcessor(sdb3, config)
  824. ptOuts3 := []*ProcessTxOutput{}
  825. for _, block := range blocks {
  826. for _, batch := range block.Rollup.Batches {
  827. ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
  828. require.NoError(t, err)
  829. ptOuts3 = append(ptOuts3, ptOut)
  830. }
  831. }
  832. return ptOuts, ptOuts2, ptOuts3
  833. }
  834. func TestTwoExitsSynchronizer(t *testing.T) {
  835. ptOuts, ptOuts2, ptOuts3 := testTwoExits(t, statedb.TypeSynchronizer)
  836. assert.Equal(t, 1, len(ptOuts[3].ExitInfos))
  837. assert.Equal(t, big.NewInt(40), ptOuts[3].ExitInfos[0].Balance)
  838. assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts2[3].ExitInfos[0].MerkleProof)
  839. assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts3[3].ExitInfos[0].MerkleProof)
  840. }
  841. func TestExitOf0Amount(t *testing.T) {
  842. // Test to check that when doing an Exit with amount 0 the Exit Root
  843. // does not change (as there is no new Exit Leaf created)
  844. dir, err := ioutil.TempDir("", "tmpdb")
  845. require.NoError(t, err)
  846. defer assert.NoError(t, os.RemoveAll(dir))
  847. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  848. Type: statedb.TypeBatchBuilder, NLevels: 32})
  849. assert.NoError(t, err)
  850. chainID := uint16(1)
  851. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  852. set := `
  853. Type: Blockchain
  854. CreateAccountDeposit(0) A: 100
  855. CreateAccountDeposit(0) B: 100
  856. > batchL1 // batch1: freeze L1User{2}
  857. > batchL1 // batch2: forge L1User{2}
  858. ForceExit(0) A: 10
  859. ForceExit(0) B: 0
  860. > batchL1 // batch3: freeze L1User{2}
  861. > batchL1 // batch4: forge L1User{2}
  862. ForceExit(0) A: 10
  863. > batchL1 // batch5: freeze L1User{1}
  864. > batchL1 // batch6: forge L1User{1}
  865. ForceExit(0) A: 0
  866. > batchL1 // batch7: freeze L1User{1}
  867. > batchL1 // batch8: forge L1User{1}
  868. > block
  869. `
  870. blocks, err := tc.GenerateBlocks(set)
  871. require.NoError(t, err)
  872. err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
  873. require.NoError(t, err)
  874. err = tc.FillBlocksForgedL1UserTxs(blocks)
  875. require.NoError(t, err)
  876. // Sanity check
  877. require.Equal(t, 2, len(blocks[0].Rollup.Batches[1].L1UserTxs))
  878. require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
  879. require.Equal(t, big.NewInt(10), blocks[0].Rollup.Batches[3].L1UserTxs[0].Amount)
  880. require.Equal(t, big.NewInt(0), blocks[0].Rollup.Batches[3].L1UserTxs[1].Amount)
  881. config := Config{
  882. NLevels: 32,
  883. MaxFeeTx: 64,
  884. MaxTx: 512,
  885. MaxL1Tx: 16,
  886. ChainID: chainID,
  887. }
  888. tp := NewTxProcessor(sdb, config)
  889. // For this test are only processed the batches with transactions:
  890. // - Batch2, equivalent to Batches[1]
  891. // - Batch4, equivalent to Batches[3]
  892. // - Batch6, equivalent to Batches[5]
  893. // - Batch8, equivalent to Batches[7]
  894. // process Batch2:
  895. _, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[1].L1UserTxs, nil, nil)
  896. require.NoError(t, err)
  897. // process Batch4:
  898. ptOut, err := tp.ProcessTxs(nil, blocks[0].Rollup.Batches[3].L1UserTxs, nil, nil)
  899. require.NoError(t, err)
  900. assert.Equal(t, "14329759303391468223438874789317921522067594445474390443816827472846339238908", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
  901. exitRootBatch4 := ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String()
  902. // process Batch6:
  903. ptOut, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[5].L1UserTxs, nil, nil)
  904. require.NoError(t, err)
  905. assert.Equal(t, "14329759303391468223438874789317921522067594445474390443816827472846339238908", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
  906. // Expect that the ExitRoot for the Batch6 will be equal than for the
  907. // Batch4, as the Batch4 & Batch6 have the same tx with Exit Amount=10,
  908. // and Batch4 has a 2nd tx with Exit Amount=0.
  909. assert.Equal(t, exitRootBatch4, ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
  910. // For the Batch8, as there is only 1 exit with Amount=0, the ExitRoot
  911. // should be 0.
  912. // process Batch8:
  913. ptOut, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[7].L1UserTxs, nil, nil)
  914. require.NoError(t, err)
  915. assert.Equal(t, "0", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
  916. }
  917. func TestUpdatedAccounts(t *testing.T) {
  918. dir, err := ioutil.TempDir("", "tmpdb")
  919. require.NoError(t, err)
  920. defer assert.NoError(t, os.RemoveAll(dir))
  921. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  922. Type: statedb.TypeSynchronizer, NLevels: 32})
  923. assert.NoError(t, err)
  924. set := `
  925. Type: Blockchain
  926. AddToken(1)
  927. CreateAccountCoordinator(0) Coord // 256
  928. CreateAccountCoordinator(1) Coord // 257
  929. > batch // 1
  930. CreateAccountDeposit(0) A: 50 // 258
  931. CreateAccountDeposit(0) B: 60 // 259
  932. CreateAccountDeposit(1) A: 70 // 260
  933. CreateAccountDeposit(1) B: 80 // 261
  934. > batchL1 // 2
  935. > batchL1 // 3
  936. Transfer(0) A-B: 5 (126)
  937. > batch // 4
  938. Exit(1) B: 5 (126)
  939. > batch // 5
  940. > block
  941. `
  942. chainID := uint16(0)
  943. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  944. blocks, err := tc.GenerateBlocks(set)
  945. require.NoError(t, err)
  946. tilCfgExtra := til.ConfigExtra{
  947. BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
  948. CoordUser: "Coord",
  949. }
  950. err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
  951. require.NoError(t, err)
  952. tc.FillBlocksL1UserTxsBatchNum(blocks)
  953. err = tc.FillBlocksForgedL1UserTxs(blocks)
  954. require.NoError(t, err)
  955. require.Equal(t, 5, len(blocks[0].Rollup.Batches))
  956. config := Config{
  957. NLevels: 32,
  958. MaxFeeTx: 64,
  959. MaxTx: 512,
  960. MaxL1Tx: 16,
  961. ChainID: chainID,
  962. }
  963. tp := NewTxProcessor(sdb, config)
  964. sortedKeys := func(m map[common.Idx]*common.Account) []int {
  965. keys := make([]int, 0)
  966. for k := range m {
  967. keys = append(keys, int(k))
  968. }
  969. sort.Ints(keys)
  970. return keys
  971. }
  972. for _, batch := range blocks[0].Rollup.Batches {
  973. l2Txs := common.L2TxsToPoolL2Txs(batch.L2Txs)
  974. ptOut, err := tp.ProcessTxs(batch.Batch.FeeIdxsCoordinator, batch.L1UserTxs,
  975. batch.L1CoordinatorTxs, l2Txs)
  976. require.NoError(t, err)
  977. switch batch.Batch.BatchNum {
  978. case 1:
  979. assert.Equal(t, 2, len(ptOut.UpdatedAccounts))
  980. assert.Equal(t, []int{256, 257}, sortedKeys(ptOut.UpdatedAccounts))
  981. case 2:
  982. assert.Equal(t, 0, len(ptOut.UpdatedAccounts))
  983. assert.Equal(t, []int{}, sortedKeys(ptOut.UpdatedAccounts))
  984. case 3:
  985. assert.Equal(t, 4, len(ptOut.UpdatedAccounts))
  986. assert.Equal(t, []int{258, 259, 260, 261}, sortedKeys(ptOut.UpdatedAccounts))
  987. case 4:
  988. assert.Equal(t, 2+1, len(ptOut.UpdatedAccounts))
  989. assert.Equal(t, []int{256, 258, 259}, sortedKeys(ptOut.UpdatedAccounts))
  990. case 5:
  991. assert.Equal(t, 1+1, len(ptOut.UpdatedAccounts))
  992. assert.Equal(t, []int{257, 261}, sortedKeys(ptOut.UpdatedAccounts))
  993. }
  994. for idx, updAcc := range ptOut.UpdatedAccounts {
  995. acc, err := sdb.GetAccount(idx)
  996. require.NoError(t, err)
  997. // If acc.Balance is 0, set it to 0 with big.NewInt so
  998. // that the comparison succeeds. Without this, the
  999. // comparison will not succeed because acc.Balance is
  1000. // set from a slice, and thus the internal big.Int
  1001. // buffer is not nil (big.Int.abs)
  1002. if acc.Balance.BitLen() == 0 {
  1003. acc.Balance = big.NewInt(0)
  1004. }
  1005. assert.Equal(t, acc, updAcc)
  1006. }
  1007. }
  1008. }