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.

913 lines
32 KiB

  1. package txprocessor
  2. import (
  3. "io/ioutil"
  4. "math/big"
  5. "os"
  6. "testing"
  7. ethCommon "github.com/ethereum/go-ethereum/common"
  8. "github.com/hermeznetwork/hermez-node/common"
  9. "github.com/hermeznetwork/hermez-node/db/statedb"
  10. "github.com/hermeznetwork/hermez-node/log"
  11. "github.com/hermeznetwork/hermez-node/test/til"
  12. "github.com/hermeznetwork/hermez-node/test/txsets"
  13. "github.com/stretchr/testify/assert"
  14. "github.com/stretchr/testify/require"
  15. )
  16. func checkBalance(t *testing.T, tc *til.Context, sdb *statedb.StateDB, username string, tokenid int, expected string) {
  17. idx := tc.Users[username].Accounts[common.TokenID(tokenid)].Idx
  18. acc, err := sdb.GetAccount(idx)
  19. require.NoError(t, err)
  20. assert.Equal(t, expected, acc.Balance.String())
  21. }
  22. func checkBalanceByIdx(t *testing.T, sdb *statedb.StateDB, idx common.Idx, expected string) {
  23. acc, err := sdb.GetAccount(idx)
  24. require.NoError(t, err)
  25. assert.Equal(t, expected, acc.Balance.String())
  26. }
  27. func TestComputeEffectiveAmounts(t *testing.T) {
  28. dir, err := ioutil.TempDir("", "tmpdb")
  29. require.NoError(t, err)
  30. defer assert.NoError(t, os.RemoveAll(dir))
  31. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  32. Type: statedb.TypeSynchronizer, NLevels: 32})
  33. assert.NoError(t, err)
  34. set := `
  35. Type: Blockchain
  36. AddToken(1)
  37. CreateAccountDeposit(0) A: 10
  38. CreateAccountDeposit(0) B: 10
  39. CreateAccountDeposit(1) C: 10
  40. > batchL1
  41. > batchL1
  42. > block
  43. `
  44. chainID := uint16(0)
  45. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  46. blocks, err := tc.GenerateBlocks(set)
  47. require.NoError(t, err)
  48. config := Config{
  49. NLevels: 32,
  50. MaxFeeTx: 64,
  51. MaxTx: 512,
  52. MaxL1Tx: 16,
  53. ChainID: chainID,
  54. }
  55. tp := NewTxProcessor(sdb, config)
  56. _, err = tp.ProcessTxs(nil, blocks[0].Rollup.L1UserTxs, nil, nil)
  57. require.NoError(t, err)
  58. tx := common.L1Tx{
  59. FromIdx: 256,
  60. ToIdx: 257,
  61. Amount: big.NewInt(10),
  62. DepositAmount: big.NewInt(0),
  63. FromEthAddr: tc.Users["A"].Addr,
  64. UserOrigin: true,
  65. }
  66. tp.computeEffectiveAmounts(&tx)
  67. assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  68. assert.Equal(t, big.NewInt(10), tx.EffectiveAmount)
  69. // expect error due not enough funds
  70. tx = common.L1Tx{
  71. FromIdx: 256,
  72. ToIdx: 257,
  73. Amount: big.NewInt(11),
  74. DepositAmount: big.NewInt(0),
  75. FromEthAddr: tc.Users["A"].Addr,
  76. UserOrigin: true,
  77. }
  78. tp.computeEffectiveAmounts(&tx)
  79. assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  80. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  81. // expect no-error as there are enough funds in a
  82. // CreateAccountDepositTransfer transction
  83. tx = common.L1Tx{
  84. FromIdx: 0,
  85. ToIdx: 257,
  86. Amount: big.NewInt(10),
  87. DepositAmount: big.NewInt(10),
  88. UserOrigin: true,
  89. }
  90. tp.computeEffectiveAmounts(&tx)
  91. assert.Equal(t, big.NewInt(10), tx.EffectiveDepositAmount)
  92. assert.Equal(t, big.NewInt(10), tx.EffectiveAmount)
  93. // expect error due not enough funds in a CreateAccountDepositTransfer
  94. // transction
  95. tx = common.L1Tx{
  96. FromIdx: 0,
  97. ToIdx: 257,
  98. Amount: big.NewInt(11),
  99. DepositAmount: big.NewInt(10),
  100. UserOrigin: true,
  101. }
  102. tp.computeEffectiveAmounts(&tx)
  103. assert.Equal(t, big.NewInt(10), tx.EffectiveDepositAmount)
  104. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  105. // expect error due not same TokenID
  106. tx = common.L1Tx{
  107. FromIdx: 256,
  108. ToIdx: 258,
  109. Amount: big.NewInt(5),
  110. DepositAmount: big.NewInt(0),
  111. FromEthAddr: tc.Users["A"].Addr,
  112. UserOrigin: true,
  113. }
  114. tp.computeEffectiveAmounts(&tx)
  115. assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  116. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  117. // expect error due not same EthAddr
  118. tx = common.L1Tx{
  119. FromIdx: 256,
  120. ToIdx: 257,
  121. Amount: big.NewInt(8),
  122. DepositAmount: big.NewInt(0),
  123. FromEthAddr: tc.Users["B"].Addr,
  124. UserOrigin: true,
  125. }
  126. tp.computeEffectiveAmounts(&tx)
  127. assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  128. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  129. // expect on TxTypeDepositTransfer EffectiveAmount=0, but
  130. // EffectiveDepositAmount!=0, due not enough funds to make the transfer
  131. tx = common.L1Tx{
  132. FromIdx: 256,
  133. ToIdx: 257,
  134. Amount: big.NewInt(20),
  135. DepositAmount: big.NewInt(8),
  136. FromEthAddr: tc.Users["A"].Addr,
  137. UserOrigin: true,
  138. }
  139. tp.computeEffectiveAmounts(&tx)
  140. assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
  141. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  142. // expect on TxTypeDepositTransfer EffectiveAmount=0, but
  143. // EffectiveDepositAmount!=0, due different EthAddr from FromIdx
  144. // address
  145. tx = common.L1Tx{
  146. FromIdx: 256,
  147. ToIdx: 257,
  148. Amount: big.NewInt(8),
  149. DepositAmount: big.NewInt(8),
  150. FromEthAddr: tc.Users["B"].Addr,
  151. UserOrigin: true,
  152. }
  153. tp.computeEffectiveAmounts(&tx)
  154. assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
  155. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  156. // CreateAccountDepositTransfer for TokenID=1 when receiver does not
  157. // have an account for that TokenID, expect that the
  158. // EffectiveDepositAmount=DepositAmount, but EffectiveAmount==0
  159. tx = common.L1Tx{
  160. FromIdx: 0,
  161. ToIdx: 257,
  162. Amount: big.NewInt(8),
  163. DepositAmount: big.NewInt(8),
  164. FromEthAddr: tc.Users["A"].Addr,
  165. TokenID: 2,
  166. UserOrigin: true,
  167. Type: common.TxTypeCreateAccountDepositTransfer,
  168. }
  169. tp.computeEffectiveAmounts(&tx)
  170. assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
  171. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  172. // DepositTransfer for TokenID=1 when receiver does not have an account
  173. // for that TokenID, expect that the
  174. // EffectiveDepositAmount=DepositAmount, but EffectiveAmount=0
  175. tx = common.L1Tx{
  176. FromIdx: 258,
  177. ToIdx: 256,
  178. Amount: big.NewInt(8),
  179. DepositAmount: big.NewInt(8),
  180. FromEthAddr: tc.Users["C"].Addr,
  181. TokenID: 1,
  182. UserOrigin: true,
  183. Type: common.TxTypeDepositTransfer,
  184. }
  185. tp.computeEffectiveAmounts(&tx)
  186. assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
  187. assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  188. }
  189. func TestProcessTxsBalances(t *testing.T) {
  190. dir, err := ioutil.TempDir("", "tmpdb")
  191. require.NoError(t, err)
  192. defer assert.NoError(t, os.RemoveAll(dir))
  193. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  194. Type: statedb.TypeSynchronizer, NLevels: 32})
  195. assert.NoError(t, err)
  196. chainID := uint16(0)
  197. // generate test transactions from test.SetBlockchain0 code
  198. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  199. blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
  200. require.NoError(t, err)
  201. config := Config{
  202. NLevels: 32,
  203. MaxFeeTx: 64,
  204. MaxTx: 512,
  205. MaxL1Tx: 16,
  206. ChainID: chainID,
  207. }
  208. tp := NewTxProcessor(sdb, config)
  209. log.Debug("block:0 batch:1, only L1CoordinatorTxs")
  210. _, err = tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
  211. require.NoError(t, err)
  212. assert.Equal(t, "0", tp.s.MT.Root().BigInt().String())
  213. log.Debug("block:0 batch:2")
  214. l1UserTxs := []common.L1Tx{}
  215. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  216. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  217. require.NoError(t, err)
  218. assert.Equal(t, "0", tp.s.MT.Root().BigInt().String())
  219. log.Debug("block:0 batch:3")
  220. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
  221. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
  222. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
  223. require.NoError(t, err)
  224. checkBalance(t, tc, sdb, "A", 0, "500")
  225. assert.Equal(t, "13644148972047617726265275926674266298636745191961029124811988256139761111521", tp.s.MT.Root().BigInt().String())
  226. log.Debug("block:0 batch:4")
  227. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
  228. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[3].L2Txs)
  229. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[3].L1CoordinatorTxs, l2Txs)
  230. require.NoError(t, err)
  231. checkBalance(t, tc, sdb, "A", 0, "500")
  232. checkBalance(t, tc, sdb, "A", 1, "500")
  233. assert.Equal(t, "12433441613247342495680642890662773367605896324555599297255745922589338651261", tp.s.MT.Root().BigInt().String())
  234. log.Debug("block:0 batch:5")
  235. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
  236. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[4].L2Txs)
  237. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[4].L1CoordinatorTxs, l2Txs)
  238. require.NoError(t, err)
  239. checkBalance(t, tc, sdb, "A", 0, "500")
  240. checkBalance(t, tc, sdb, "A", 1, "500")
  241. assert.Equal(t, "12433441613247342495680642890662773367605896324555599297255745922589338651261", tp.s.MT.Root().BigInt().String())
  242. log.Debug("block:0 batch:6")
  243. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
  244. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[5].L2Txs)
  245. _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[5].L1CoordinatorTxs, l2Txs)
  246. require.NoError(t, err)
  247. checkBalance(t, tc, sdb, "A", 0, "600")
  248. checkBalance(t, tc, sdb, "A", 1, "500")
  249. checkBalance(t, tc, sdb, "B", 0, "400")
  250. assert.Equal(t, "4191361650490017591061467288209836928064232431729236465872209988325272262963", tp.s.MT.Root().BigInt().String())
  251. coordIdxs := []common.Idx{261, 262}
  252. log.Debug("block:0 batch:7")
  253. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
  254. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[6].L2Txs)
  255. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[6].L1CoordinatorTxs, l2Txs)
  256. require.NoError(t, err)
  257. checkBalance(t, tc, sdb, "Coord", 0, "10")
  258. checkBalance(t, tc, sdb, "Coord", 1, "20")
  259. checkBalance(t, tc, sdb, "A", 0, "600")
  260. checkBalance(t, tc, sdb, "A", 1, "280")
  261. checkBalance(t, tc, sdb, "B", 0, "290")
  262. checkBalance(t, tc, sdb, "B", 1, "200")
  263. checkBalance(t, tc, sdb, "C", 0, "100")
  264. checkBalance(t, tc, sdb, "D", 0, "800")
  265. assert.Equal(t, "7614010373759339299470010949167613050707822522530721724565424494781010548240", tp.s.MT.Root().BigInt().String())
  266. log.Debug("block:0 batch:8")
  267. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
  268. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[7].L2Txs)
  269. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[7].L1CoordinatorTxs, l2Txs)
  270. require.NoError(t, err)
  271. checkBalance(t, tc, sdb, "Coord", 0, "35")
  272. checkBalance(t, tc, sdb, "Coord", 1, "30")
  273. checkBalance(t, tc, sdb, "A", 0, "430")
  274. checkBalance(t, tc, sdb, "A", 1, "280")
  275. checkBalance(t, tc, sdb, "B", 0, "390")
  276. checkBalance(t, tc, sdb, "B", 1, "90")
  277. checkBalance(t, tc, sdb, "C", 0, "45")
  278. checkBalance(t, tc, sdb, "C", 1, "100")
  279. checkBalance(t, tc, sdb, "D", 0, "800")
  280. assert.Equal(t, "21231789250434471575486264439945776732824482207853465397552873521865656677689", tp.s.MT.Root().BigInt().String())
  281. coordIdxs = []common.Idx{262}
  282. log.Debug("block:1 batch:1")
  283. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
  284. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
  285. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
  286. require.NoError(t, err)
  287. checkBalance(t, tc, sdb, "Coord", 0, "75")
  288. checkBalance(t, tc, sdb, "Coord", 1, "30")
  289. checkBalance(t, tc, sdb, "A", 0, "730")
  290. checkBalance(t, tc, sdb, "A", 1, "280")
  291. checkBalance(t, tc, sdb, "B", 0, "380")
  292. checkBalance(t, tc, sdb, "B", 1, "90")
  293. checkBalance(t, tc, sdb, "C", 0, "845")
  294. checkBalance(t, tc, sdb, "C", 1, "100")
  295. checkBalance(t, tc, sdb, "D", 0, "470")
  296. assert.Equal(t, "11289313644810782435120113035387729451095637380468777086895109386127538554246", tp.s.MT.Root().BigInt().String())
  297. coordIdxs = []common.Idx{}
  298. log.Debug("block:1 batch:2")
  299. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  300. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
  301. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  302. require.NoError(t, err)
  303. assert.Equal(t, "10342681351319338354912862547249967104198317571995055517008223832276478908482", tp.s.MT.Root().BigInt().String())
  304. // use Set of PoolL2 txs
  305. poolL2Txs, err := tc.GeneratePoolL2Txs(txsets.SetPoolL2MinimumFlow1)
  306. assert.NoError(t, err)
  307. _, err = tp.ProcessTxs(coordIdxs, []common.L1Tx{}, []common.L1Tx{}, poolL2Txs)
  308. require.NoError(t, err)
  309. checkBalance(t, tc, sdb, "Coord", 0, "75")
  310. checkBalance(t, tc, sdb, "Coord", 1, "30")
  311. checkBalance(t, tc, sdb, "A", 0, "510")
  312. checkBalance(t, tc, sdb, "A", 1, "170")
  313. checkBalance(t, tc, sdb, "B", 0, "480")
  314. checkBalance(t, tc, sdb, "B", 1, "190")
  315. checkBalance(t, tc, sdb, "C", 0, "845")
  316. checkBalance(t, tc, sdb, "C", 1, "100")
  317. checkBalance(t, tc, sdb, "D", 0, "360")
  318. checkBalance(t, tc, sdb, "F", 0, "100")
  319. }
  320. func TestProcessTxsSynchronizer(t *testing.T) {
  321. dir, err := ioutil.TempDir("", "tmpdb")
  322. require.NoError(t, err)
  323. defer assert.NoError(t, os.RemoveAll(dir))
  324. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  325. Type: statedb.TypeSynchronizer, NLevels: 32})
  326. assert.NoError(t, err)
  327. chainID := uint16(0)
  328. // generate test transactions from test.SetBlockchain0 code
  329. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  330. blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
  331. require.NoError(t, err)
  332. assert.Equal(t, 31, len(blocks[0].Rollup.L1UserTxs))
  333. assert.Equal(t, 4, len(blocks[0].Rollup.Batches[0].L1CoordinatorTxs))
  334. assert.Equal(t, 0, len(blocks[0].Rollup.Batches[1].L1CoordinatorTxs))
  335. assert.Equal(t, 22, len(blocks[0].Rollup.Batches[2].L2Txs))
  336. assert.Equal(t, 1, len(blocks[1].Rollup.Batches[0].L1CoordinatorTxs))
  337. assert.Equal(t, 62, len(blocks[1].Rollup.Batches[0].L2Txs))
  338. assert.Equal(t, 1, len(blocks[1].Rollup.Batches[1].L1CoordinatorTxs))
  339. assert.Equal(t, 8, len(blocks[1].Rollup.Batches[1].L2Txs))
  340. // Coordinator Idx where to send the fees
  341. coordIdxs := []common.Idx{256, 257, 258, 259}
  342. // Idx of user 'A'
  343. idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
  344. config := Config{
  345. NLevels: 32,
  346. MaxFeeTx: 64,
  347. MaxTx: 512,
  348. MaxL1Tx: 32,
  349. ChainID: chainID,
  350. }
  351. tp := NewTxProcessor(sdb, config)
  352. // Process the 1st batch, which contains the L1CoordinatorTxs necessary
  353. // to create the Coordinator accounts to receive the fees
  354. log.Debug("block:0 batch:1, only L1CoordinatorTxs")
  355. ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
  356. require.NoError(t, err)
  357. assert.Equal(t, 4, len(ptOut.CreatedAccounts))
  358. assert.Equal(t, 0, len(ptOut.CollectedFees))
  359. log.Debug("block:0 batch:2")
  360. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  361. ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs,
  362. blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  363. require.NoError(t, err)
  364. assert.Equal(t, 0, len(ptOut.ExitInfos))
  365. assert.Equal(t, 31, len(ptOut.CreatedAccounts))
  366. assert.Equal(t, 4, len(ptOut.CollectedFees))
  367. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
  368. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
  369. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  370. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  371. acc, err := sdb.GetAccount(idxA1)
  372. require.NoError(t, err)
  373. assert.Equal(t, "50", acc.Balance.String())
  374. log.Debug("block:0 batch:3")
  375. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
  376. ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
  377. require.NoError(t, err)
  378. assert.Equal(t, 0, len(ptOut.ExitInfos))
  379. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  380. assert.Equal(t, 4, len(ptOut.CollectedFees))
  381. assert.Equal(t, "2", ptOut.CollectedFees[common.TokenID(0)].String())
  382. assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
  383. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  384. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  385. acc, err = sdb.GetAccount(idxA1)
  386. require.NoError(t, err)
  387. assert.Equal(t, "35", acc.Balance.String())
  388. log.Debug("block:1 batch:1")
  389. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
  390. // before processing expect l2Txs[0:2].Nonce==0
  391. assert.Equal(t, common.Nonce(0), l2Txs[0].Nonce)
  392. assert.Equal(t, common.Nonce(0), l2Txs[1].Nonce)
  393. assert.Equal(t, common.Nonce(0), l2Txs[2].Nonce)
  394. ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
  395. require.NoError(t, err)
  396. // after processing expect l2Txs[0:2].Nonce!=0 and has expected value
  397. assert.Equal(t, common.Nonce(5), l2Txs[0].Nonce)
  398. assert.Equal(t, common.Nonce(6), l2Txs[1].Nonce)
  399. assert.Equal(t, common.Nonce(7), l2Txs[2].Nonce)
  400. assert.Equal(t, 4, len(ptOut.ExitInfos)) // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs
  401. assert.Equal(t, 1, len(ptOut.CreatedAccounts))
  402. assert.Equal(t, 4, len(ptOut.CollectedFees))
  403. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
  404. assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
  405. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  406. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  407. acc, err = sdb.GetAccount(idxA1)
  408. require.NoError(t, err)
  409. assert.Equal(t, "57", acc.Balance.String())
  410. log.Debug("block:1 batch:2")
  411. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
  412. ptOut, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs,
  413. blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  414. require.NoError(t, err)
  415. 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
  416. assert.Equal(t, 1, len(ptOut.CreatedAccounts))
  417. assert.Equal(t, 4, len(ptOut.CollectedFees))
  418. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
  419. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
  420. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  421. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  422. acc, err = sdb.GetAccount(idxA1)
  423. assert.NoError(t, err)
  424. assert.Equal(t, "77", acc.Balance.String())
  425. idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
  426. acc, err = sdb.GetAccount(idxB0)
  427. require.NoError(t, err)
  428. assert.Equal(t, "51", acc.Balance.String())
  429. // get balance of Coordinator account for TokenID==0
  430. acc, err = sdb.GetAccount(common.Idx(256))
  431. require.NoError(t, err)
  432. assert.Equal(t, "2", acc.Balance.String())
  433. }
  434. func TestProcessTxsBatchBuilder(t *testing.T) {
  435. dir, err := ioutil.TempDir("", "tmpdb")
  436. require.NoError(t, err)
  437. defer assert.NoError(t, os.RemoveAll(dir))
  438. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  439. Type: statedb.TypeBatchBuilder, NLevels: 32})
  440. assert.NoError(t, err)
  441. chainID := uint16(0)
  442. // generate test transactions from test.SetBlockchain0 code
  443. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  444. blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
  445. require.NoError(t, err)
  446. // Coordinator Idx where to send the fees
  447. coordIdxs := []common.Idx{256, 257, 258, 259}
  448. // Idx of user 'A'
  449. idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
  450. config := Config{
  451. NLevels: 32,
  452. MaxFeeTx: 64,
  453. MaxTx: 512,
  454. MaxL1Tx: 32,
  455. ChainID: chainID,
  456. }
  457. tp := NewTxProcessor(sdb, config)
  458. // Process the 1st batch, which contains the L1CoordinatorTxs necessary
  459. // to create the Coordinator accounts to receive the fees
  460. log.Debug("block:0 batch:1, only L1CoordinatorTxs")
  461. ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
  462. require.NoError(t, err)
  463. // expect 0 at CreatedAccount, as is only computed when StateDB.Type==TypeSynchronizer
  464. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  465. log.Debug("block:0 batch:2")
  466. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  467. ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  468. require.NoError(t, err)
  469. assert.Equal(t, 0, len(ptOut.ExitInfos))
  470. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  471. acc, err := sdb.GetAccount(idxA1)
  472. require.NoError(t, err)
  473. assert.Equal(t, "50", acc.Balance.String())
  474. log.Debug("block:0 batch:3")
  475. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
  476. ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
  477. require.NoError(t, err)
  478. assert.Equal(t, 0, len(ptOut.ExitInfos))
  479. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  480. acc, err = sdb.GetAccount(idxA1)
  481. require.NoError(t, err)
  482. assert.Equal(t, "35", acc.Balance.String())
  483. log.Debug("block:1 batch:1")
  484. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
  485. _, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
  486. require.NoError(t, err)
  487. acc, err = sdb.GetAccount(idxA1)
  488. require.NoError(t, err)
  489. assert.Equal(t, "57", acc.Balance.String())
  490. log.Debug("block:1 batch:2")
  491. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
  492. _, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  493. require.NoError(t, err)
  494. acc, err = sdb.GetAccount(idxA1)
  495. assert.NoError(t, err)
  496. assert.Equal(t, "77", acc.Balance.String())
  497. idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
  498. acc, err = sdb.GetAccount(idxB0)
  499. require.NoError(t, err)
  500. assert.Equal(t, "51", acc.Balance.String())
  501. // get balance of Coordinator account for TokenID==0
  502. acc, err = sdb.GetAccount(common.Idx(256))
  503. require.NoError(t, err)
  504. assert.Equal(t, common.TokenID(0), acc.TokenID)
  505. assert.Equal(t, "2", acc.Balance.String())
  506. acc, err = sdb.GetAccount(common.Idx(257))
  507. require.NoError(t, err)
  508. assert.Equal(t, common.TokenID(1), acc.TokenID)
  509. assert.Equal(t, "2", acc.Balance.String())
  510. assert.Equal(t, "18894163991492573893706613133132363559300580460789469708968288074813925659539", sdb.MT.Root().BigInt().String())
  511. }
  512. func TestProcessTxsRootTestVectors(t *testing.T) {
  513. dir, err := ioutil.TempDir("", "tmpdb")
  514. require.NoError(t, err)
  515. defer assert.NoError(t, os.RemoveAll(dir))
  516. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  517. Type: statedb.TypeBatchBuilder, NLevels: 32})
  518. assert.NoError(t, err)
  519. // same values than in the js test
  520. bjj0, err := common.BJJFromStringWithChecksum("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7")
  521. assert.NoError(t, err)
  522. l1Txs := []common.L1Tx{
  523. {
  524. FromIdx: 0,
  525. DepositAmount: big.NewInt(16000000),
  526. Amount: big.NewInt(0),
  527. TokenID: 1,
  528. FromBJJ: bjj0,
  529. FromEthAddr: ethCommon.HexToAddress("0x7e5f4552091a69125d5dfcb7b8c2659029395bdf"),
  530. ToIdx: 0,
  531. Type: common.TxTypeCreateAccountDeposit,
  532. UserOrigin: true,
  533. },
  534. }
  535. l2Txs := []common.PoolL2Tx{
  536. {
  537. FromIdx: 256,
  538. ToIdx: 256,
  539. TokenID: 1,
  540. Amount: big.NewInt(1000),
  541. Nonce: 0,
  542. Fee: 126,
  543. Type: common.TxTypeTransfer,
  544. },
  545. }
  546. chainID := uint16(0)
  547. config := Config{
  548. NLevels: 32,
  549. MaxFeeTx: 8,
  550. MaxTx: 32,
  551. MaxL1Tx: 16,
  552. ChainID: chainID,
  553. }
  554. tp := NewTxProcessor(sdb, config)
  555. _, err = tp.ProcessTxs(nil, l1Txs, nil, l2Txs)
  556. require.NoError(t, err)
  557. assert.Equal(t, "9827704113668630072730115158977131501210702363656902211840117643154933433410", sdb.MT.Root().BigInt().String())
  558. }
  559. func TestCreateAccountDepositMaxValue(t *testing.T) {
  560. dir, err := ioutil.TempDir("", "tmpdb")
  561. require.NoError(t, err)
  562. defer assert.NoError(t, os.RemoveAll(dir))
  563. nLevels := 16
  564. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  565. Type: statedb.TypeBatchBuilder, NLevels: nLevels})
  566. assert.NoError(t, err)
  567. users := txsets.GenerateJsUsers(t)
  568. daMaxF40 := common.Float40(0xFFFFFFFFFF)
  569. daMaxBI, err := daMaxF40.BigInt()
  570. require.NoError(t, err)
  571. assert.Equal(t, "343597383670000000000000000000000000000000", daMaxBI.String())
  572. daMax1F40 := common.Float40(0xFFFFFFFFFE)
  573. require.NoError(t, err)
  574. daMax1BI, err := daMax1F40.BigInt()
  575. require.NoError(t, err)
  576. assert.Equal(t, "343597383660000000000000000000000000000000", daMax1BI.String())
  577. l1Txs := []common.L1Tx{
  578. {
  579. FromIdx: 0,
  580. DepositAmount: daMaxBI,
  581. Amount: big.NewInt(0),
  582. TokenID: 1,
  583. FromBJJ: users[0].BJJ.Public().Compress(),
  584. FromEthAddr: users[0].Addr,
  585. ToIdx: 0,
  586. Type: common.TxTypeCreateAccountDeposit,
  587. UserOrigin: true,
  588. },
  589. {
  590. FromIdx: 0,
  591. DepositAmount: daMax1BI,
  592. Amount: big.NewInt(0),
  593. TokenID: 1,
  594. FromBJJ: users[1].BJJ.Public().Compress(),
  595. FromEthAddr: users[1].Addr,
  596. ToIdx: 0,
  597. Type: common.TxTypeCreateAccountDeposit,
  598. UserOrigin: true,
  599. },
  600. }
  601. chainID := uint16(0)
  602. config := Config{
  603. NLevels: uint32(nLevels),
  604. MaxTx: 3,
  605. MaxL1Tx: 2,
  606. MaxFeeTx: 2,
  607. ChainID: chainID,
  608. }
  609. tp := NewTxProcessor(sdb, config)
  610. _, err = tp.ProcessTxs(nil, l1Txs, nil, nil)
  611. require.NoError(t, err)
  612. // check balances
  613. acc, err := sdb.GetAccount(common.Idx(256))
  614. require.NoError(t, err)
  615. assert.Equal(t, daMaxBI, acc.Balance)
  616. acc, err = sdb.GetAccount(common.Idx(257))
  617. require.NoError(t, err)
  618. assert.Equal(t, daMax1BI, acc.Balance)
  619. }
  620. func initTestMultipleCoordIdxForTokenID(t *testing.T) (*TxProcessor, *til.Context, []common.BlockData) {
  621. dir, err := ioutil.TempDir("", "tmpdb")
  622. require.NoError(t, err)
  623. defer assert.NoError(t, os.RemoveAll(dir))
  624. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  625. Type: statedb.TypeBatchBuilder, NLevels: 32})
  626. assert.NoError(t, err)
  627. chainID := uint16(1)
  628. // generate test transactions from test.SetBlockchain0 code
  629. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  630. set := `
  631. Type: Blockchain
  632. CreateAccountDeposit(0) A: 200
  633. > batchL1 // freeze L1User{1}
  634. CreateAccountCoordinator(0) Coord
  635. CreateAccountCoordinator(0) B
  636. Transfer(0) A-B: 100 (126)
  637. > batchL1 // forge L1User{1}, forge L1Coord{4}, forge L2{2}
  638. > block
  639. `
  640. blocks, err := tc.GenerateBlocks(set)
  641. require.NoError(t, err)
  642. config := Config{
  643. NLevels: 32,
  644. MaxFeeTx: 64,
  645. MaxTx: 512,
  646. MaxL1Tx: 16,
  647. ChainID: chainID,
  648. }
  649. tp := NewTxProcessor(sdb, config)
  650. // batch1
  651. _, err = tp.ProcessTxs(nil, nil, nil, nil) // to simulate the first batch from the Til set
  652. require.NoError(t, err)
  653. return tp, tc, blocks
  654. }
  655. func TestMultipleCoordIdxForTokenID(t *testing.T) {
  656. // Check that ProcessTxs always uses the first occurrence of the
  657. // CoordIdx for each TokenID
  658. coordIdxs := []common.Idx{257, 257, 257}
  659. tp, tc, blocks := initTestMultipleCoordIdxForTokenID(t)
  660. l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  661. l1CoordTxs := blocks[0].Rollup.Batches[1].L1CoordinatorTxs
  662. l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
  663. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  664. _, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
  665. require.NoError(t, err)
  666. checkBalanceByIdx(t, tp.s, 256, "90") // A
  667. checkBalanceByIdx(t, tp.s, 257, "10") // Coord0
  668. checkBalanceByIdx(t, tp.s, 258, "100") // B
  669. checkBalanceByIdx(t, tp.s, 259, "0") // Coord0
  670. // reset StateDB values
  671. coordIdxs = []common.Idx{259, 257}
  672. tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
  673. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  674. l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
  675. l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
  676. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  677. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
  678. require.NoError(t, err)
  679. checkBalanceByIdx(t, tp.s, 256, "90") // A
  680. checkBalanceByIdx(t, tp.s, 257, "0") // Coord0
  681. checkBalanceByIdx(t, tp.s, 258, "100") // B
  682. checkBalanceByIdx(t, tp.s, 259, "10") // Coord0
  683. // reset StateDB values
  684. coordIdxs = []common.Idx{257, 259}
  685. tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
  686. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  687. l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
  688. l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
  689. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  690. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
  691. require.NoError(t, err)
  692. checkBalanceByIdx(t, tp.s, 256, "90") // A
  693. checkBalanceByIdx(t, tp.s, 257, "10") // Coord0
  694. checkBalanceByIdx(t, tp.s, 258, "100") // B
  695. checkBalanceByIdx(t, tp.s, 259, "0") // Coord0
  696. }
  697. func TestTwoExits(t *testing.T) {
  698. // In the first part we generate a batch with two force exits for the
  699. // same account of 20 each. The txprocessor output should be a single
  700. // exitInfo with balance of 40.
  701. dir, err := ioutil.TempDir("", "tmpdb")
  702. require.NoError(t, err)
  703. defer assert.NoError(t, os.RemoveAll(dir))
  704. sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  705. Type: statedb.TypeSynchronizer, NLevels: 32})
  706. assert.NoError(t, err)
  707. chainID := uint16(1)
  708. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  709. // Two exits for the same account. The tx processor should output a
  710. // single exit with the accumulated exit balance
  711. set := `
  712. Type: Blockchain
  713. CreateAccountDeposit(0) A: 100
  714. > batchL1 // freeze L1User{1}
  715. > batchL1 // forge L1User{1}
  716. ForceExit(0) A: 20
  717. ForceExit(0) A: 20
  718. > batchL1 // freeze L1User{2}
  719. > batchL1 // forge L1User{2}
  720. > block
  721. `
  722. blocks, err := tc.GenerateBlocks(set)
  723. require.NoError(t, err)
  724. err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
  725. require.NoError(t, err)
  726. err = tc.FillBlocksForgedL1UserTxs(blocks)
  727. require.NoError(t, err)
  728. // Sanity check
  729. require.Equal(t, 1, len(blocks[0].Rollup.Batches[1].L1UserTxs))
  730. require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
  731. config := Config{
  732. NLevels: 32,
  733. MaxFeeTx: 64,
  734. MaxTx: 512,
  735. MaxL1Tx: 16,
  736. ChainID: chainID,
  737. }
  738. tp := NewTxProcessor(sdb, config)
  739. ptOuts := []*ProcessTxOutput{}
  740. for _, block := range blocks {
  741. for _, batch := range block.Rollup.Batches {
  742. ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
  743. require.NoError(t, err)
  744. ptOuts = append(ptOuts, ptOut)
  745. }
  746. }
  747. assert.Equal(t, 1, len(ptOuts[3].ExitInfos))
  748. assert.Equal(t, big.NewInt(40), ptOuts[3].ExitInfos[0].Balance)
  749. acc, err := sdb.GetAccount(256)
  750. require.NoError(t, err)
  751. assert.Equal(t, big.NewInt(60), acc.Balance)
  752. // In the second part we start a fresh statedb and generate a batch
  753. // with one force exit for the same account as before. The txprocessor
  754. // output should be a single exitInfo with balance of 40, and the exit
  755. // merkle tree proof should be equal to the previous one.
  756. dir2, err := ioutil.TempDir("", "tmpdb")
  757. require.NoError(t, err)
  758. defer assert.NoError(t, os.RemoveAll(dir2))
  759. sdb2, err := statedb.NewStateDB(statedb.Config{Path: dir2, Keep: 128,
  760. Type: statedb.TypeSynchronizer, NLevels: 32})
  761. assert.NoError(t, err)
  762. tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  763. // Single exit with balance of both exits in previous set. The exit
  764. // root should match.
  765. set2 := `
  766. Type: Blockchain
  767. CreateAccountDeposit(0) A: 100
  768. > batchL1 // freeze L1User{1}
  769. > batchL1 // forge L1User{1}
  770. ForceExit(0) A: 40
  771. > batchL1 // freeze L1User{2}
  772. > batchL1 // forge L1User{2}
  773. > block
  774. `
  775. blocks, err = tc.GenerateBlocks(set2)
  776. require.NoError(t, err)
  777. err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
  778. require.NoError(t, err)
  779. err = tc.FillBlocksForgedL1UserTxs(blocks)
  780. require.NoError(t, err)
  781. tp = NewTxProcessor(sdb2, config)
  782. ptOuts2 := []*ProcessTxOutput{}
  783. for _, block := range blocks {
  784. for _, batch := range block.Rollup.Batches {
  785. ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
  786. require.NoError(t, err)
  787. ptOuts2 = append(ptOuts2, ptOut)
  788. }
  789. }
  790. assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts2[3].ExitInfos[0].MerkleProof)
  791. }