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.

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