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.

907 lines
31 KiB

  1. package txprocessor
  2. import (
  3. "encoding/binary"
  4. "encoding/hex"
  5. "io/ioutil"
  6. "math/big"
  7. "os"
  8. "testing"
  9. ethCommon "github.com/ethereum/go-ethereum/common"
  10. "github.com/hermeznetwork/hermez-node/common"
  11. "github.com/hermeznetwork/hermez-node/db/statedb"
  12. "github.com/hermeznetwork/hermez-node/log"
  13. "github.com/hermeznetwork/hermez-node/test/til"
  14. "github.com/hermeznetwork/hermez-node/test/txsets"
  15. "github.com/stretchr/testify/assert"
  16. "github.com/stretchr/testify/require"
  17. )
  18. func checkBalance(t *testing.T, tc *til.Context, sdb *statedb.StateDB, username string, 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(dir, 128, statedb.TypeSynchronizer, 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(dir, 128, statedb.TypeSynchronizer, 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(dir, 128, statedb.TypeSynchronizer, 32)
  325. assert.NoError(t, err)
  326. chainID := uint16(0)
  327. // generate test transactions from test.SetBlockchain0 code
  328. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  329. blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
  330. require.NoError(t, err)
  331. assert.Equal(t, 31, len(blocks[0].Rollup.L1UserTxs))
  332. assert.Equal(t, 4, len(blocks[0].Rollup.Batches[0].L1CoordinatorTxs))
  333. assert.Equal(t, 0, len(blocks[0].Rollup.Batches[1].L1CoordinatorTxs))
  334. assert.Equal(t, 22, len(blocks[0].Rollup.Batches[2].L2Txs))
  335. assert.Equal(t, 1, len(blocks[1].Rollup.Batches[0].L1CoordinatorTxs))
  336. assert.Equal(t, 62, len(blocks[1].Rollup.Batches[0].L2Txs))
  337. assert.Equal(t, 1, len(blocks[1].Rollup.Batches[1].L1CoordinatorTxs))
  338. assert.Equal(t, 8, len(blocks[1].Rollup.Batches[1].L2Txs))
  339. // Coordinator Idx where to send the fees
  340. coordIdxs := []common.Idx{256, 257, 258, 259}
  341. // Idx of user 'A'
  342. idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
  343. config := Config{
  344. NLevels: 32,
  345. MaxFeeTx: 64,
  346. MaxTx: 512,
  347. MaxL1Tx: 32,
  348. ChainID: chainID,
  349. }
  350. tp := NewTxProcessor(sdb, config)
  351. // Process the 1st batch, which contains the L1CoordinatorTxs necessary
  352. // to create the Coordinator accounts to receive the fees
  353. log.Debug("block:0 batch:1, only L1CoordinatorTxs")
  354. ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
  355. require.NoError(t, err)
  356. assert.Equal(t, 4, len(ptOut.CreatedAccounts))
  357. assert.Equal(t, 0, len(ptOut.CollectedFees))
  358. log.Debug("block:0 batch:2")
  359. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  360. ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs,
  361. blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  362. require.NoError(t, err)
  363. assert.Equal(t, 0, len(ptOut.ExitInfos))
  364. assert.Equal(t, 31, len(ptOut.CreatedAccounts))
  365. assert.Equal(t, 4, len(ptOut.CollectedFees))
  366. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
  367. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
  368. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  369. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  370. acc, err := sdb.GetAccount(idxA1)
  371. require.NoError(t, err)
  372. assert.Equal(t, "50", acc.Balance.String())
  373. log.Debug("block:0 batch:3")
  374. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
  375. ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
  376. require.NoError(t, err)
  377. assert.Equal(t, 0, len(ptOut.ExitInfos))
  378. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  379. assert.Equal(t, 4, len(ptOut.CollectedFees))
  380. assert.Equal(t, "2", ptOut.CollectedFees[common.TokenID(0)].String())
  381. assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
  382. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  383. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  384. acc, err = sdb.GetAccount(idxA1)
  385. require.NoError(t, err)
  386. assert.Equal(t, "35", acc.Balance.String())
  387. log.Debug("block:1 batch:1")
  388. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
  389. // before processing expect l2Txs[0:2].Nonce==0
  390. assert.Equal(t, common.Nonce(0), l2Txs[0].Nonce)
  391. assert.Equal(t, common.Nonce(0), l2Txs[1].Nonce)
  392. assert.Equal(t, common.Nonce(0), l2Txs[2].Nonce)
  393. ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
  394. require.NoError(t, err)
  395. // after processing expect l2Txs[0:2].Nonce!=0 and has expected value
  396. assert.Equal(t, common.Nonce(5), l2Txs[0].Nonce)
  397. assert.Equal(t, common.Nonce(6), l2Txs[1].Nonce)
  398. assert.Equal(t, common.Nonce(7), l2Txs[2].Nonce)
  399. assert.Equal(t, 4, len(ptOut.ExitInfos)) // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs
  400. assert.Equal(t, 1, len(ptOut.CreatedAccounts))
  401. assert.Equal(t, 4, len(ptOut.CollectedFees))
  402. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
  403. assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
  404. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  405. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  406. acc, err = sdb.GetAccount(idxA1)
  407. require.NoError(t, err)
  408. assert.Equal(t, "57", acc.Balance.String())
  409. log.Debug("block:1 batch:2")
  410. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
  411. ptOut, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs,
  412. blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  413. require.NoError(t, err)
  414. 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
  415. assert.Equal(t, 1, len(ptOut.CreatedAccounts))
  416. assert.Equal(t, 4, len(ptOut.CollectedFees))
  417. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
  418. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
  419. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
  420. assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
  421. acc, err = sdb.GetAccount(idxA1)
  422. assert.NoError(t, err)
  423. assert.Equal(t, "77", acc.Balance.String())
  424. idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
  425. acc, err = sdb.GetAccount(idxB0)
  426. require.NoError(t, err)
  427. assert.Equal(t, "51", acc.Balance.String())
  428. // get balance of Coordinator account for TokenID==0
  429. acc, err = sdb.GetAccount(common.Idx(256))
  430. require.NoError(t, err)
  431. assert.Equal(t, "2", acc.Balance.String())
  432. }
  433. func TestProcessTxsBatchBuilder(t *testing.T) {
  434. dir, err := ioutil.TempDir("", "tmpdb")
  435. require.NoError(t, err)
  436. defer assert.NoError(t, os.RemoveAll(dir))
  437. sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, 32)
  438. assert.NoError(t, err)
  439. chainID := uint16(0)
  440. // generate test transactions from test.SetBlockchain0 code
  441. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  442. blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
  443. require.NoError(t, err)
  444. // Coordinator Idx where to send the fees
  445. coordIdxs := []common.Idx{256, 257, 258, 259}
  446. // Idx of user 'A'
  447. idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
  448. config := Config{
  449. NLevels: 32,
  450. MaxFeeTx: 64,
  451. MaxTx: 512,
  452. MaxL1Tx: 32,
  453. ChainID: chainID,
  454. }
  455. tp := NewTxProcessor(sdb, config)
  456. // Process the 1st batch, which contains the L1CoordinatorTxs necessary
  457. // to create the Coordinator accounts to receive the fees
  458. log.Debug("block:0 batch:1, only L1CoordinatorTxs")
  459. ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
  460. require.NoError(t, err)
  461. // expect 0 at CreatedAccount, as is only computed when StateDB.Type==TypeSynchronizer
  462. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  463. log.Debug("block:0 batch:2")
  464. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  465. ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  466. require.NoError(t, err)
  467. assert.Equal(t, 0, len(ptOut.ExitInfos))
  468. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  469. acc, err := sdb.GetAccount(idxA1)
  470. require.NoError(t, err)
  471. assert.Equal(t, "50", acc.Balance.String())
  472. log.Debug("block:0 batch:3")
  473. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
  474. ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
  475. require.NoError(t, err)
  476. assert.Equal(t, 0, len(ptOut.ExitInfos))
  477. assert.Equal(t, 0, len(ptOut.CreatedAccounts))
  478. acc, err = sdb.GetAccount(idxA1)
  479. require.NoError(t, err)
  480. assert.Equal(t, "35", acc.Balance.String())
  481. log.Debug("block:1 batch:1")
  482. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
  483. _, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
  484. require.NoError(t, err)
  485. acc, err = sdb.GetAccount(idxA1)
  486. require.NoError(t, err)
  487. assert.Equal(t, "57", acc.Balance.String())
  488. log.Debug("block:1 batch:2")
  489. l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
  490. _, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
  491. require.NoError(t, err)
  492. acc, err = sdb.GetAccount(idxA1)
  493. assert.NoError(t, err)
  494. assert.Equal(t, "77", acc.Balance.String())
  495. idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
  496. acc, err = sdb.GetAccount(idxB0)
  497. require.NoError(t, err)
  498. assert.Equal(t, "51", acc.Balance.String())
  499. // get balance of Coordinator account for TokenID==0
  500. acc, err = sdb.GetAccount(common.Idx(256))
  501. require.NoError(t, err)
  502. assert.Equal(t, common.TokenID(0), acc.TokenID)
  503. assert.Equal(t, "2", acc.Balance.String())
  504. acc, err = sdb.GetAccount(common.Idx(257))
  505. require.NoError(t, err)
  506. assert.Equal(t, common.TokenID(1), acc.TokenID)
  507. assert.Equal(t, "2", acc.Balance.String())
  508. assert.Equal(t, "18894163991492573893706613133132363559300580460789469708968288074813925659539", sdb.MT.Root().BigInt().String())
  509. }
  510. func TestProcessTxsRootTestVectors(t *testing.T) {
  511. dir, err := ioutil.TempDir("", "tmpdb")
  512. require.NoError(t, err)
  513. defer assert.NoError(t, os.RemoveAll(dir))
  514. sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, 32)
  515. assert.NoError(t, err)
  516. // same values than in the js test
  517. bjj0, err := common.BJJFromStringWithChecksum("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7")
  518. assert.NoError(t, err)
  519. l1Txs := []common.L1Tx{
  520. {
  521. FromIdx: 0,
  522. DepositAmount: big.NewInt(16000000),
  523. Amount: big.NewInt(0),
  524. TokenID: 1,
  525. FromBJJ: bjj0,
  526. FromEthAddr: ethCommon.HexToAddress("0x7e5f4552091a69125d5dfcb7b8c2659029395bdf"),
  527. ToIdx: 0,
  528. Type: common.TxTypeCreateAccountDeposit,
  529. UserOrigin: true,
  530. },
  531. }
  532. l2Txs := []common.PoolL2Tx{
  533. {
  534. FromIdx: 256,
  535. ToIdx: 256,
  536. TokenID: 1,
  537. Amount: big.NewInt(1000),
  538. Nonce: 0,
  539. Fee: 126,
  540. Type: common.TxTypeTransfer,
  541. },
  542. }
  543. chainID := uint16(0)
  544. config := Config{
  545. NLevels: 32,
  546. MaxFeeTx: 8,
  547. MaxTx: 32,
  548. MaxL1Tx: 16,
  549. ChainID: chainID,
  550. }
  551. tp := NewTxProcessor(sdb, config)
  552. _, err = tp.ProcessTxs(nil, l1Txs, nil, l2Txs)
  553. require.NoError(t, err)
  554. assert.Equal(t, "9827704113668630072730115158977131501210702363656902211840117643154933433410", sdb.MT.Root().BigInt().String())
  555. }
  556. func TestCreateAccountDepositMaxValue(t *testing.T) {
  557. dir, err := ioutil.TempDir("", "tmpdb")
  558. require.NoError(t, err)
  559. defer assert.NoError(t, os.RemoveAll(dir))
  560. nLevels := 16
  561. sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, nLevels)
  562. assert.NoError(t, err)
  563. users := txsets.GenerateJsUsers(t)
  564. daMaxHex, err := hex.DecodeString("FFFF")
  565. require.NoError(t, err)
  566. daMaxF16 := common.Float16(binary.BigEndian.Uint16(daMaxHex))
  567. daMaxBI := daMaxF16.BigInt()
  568. assert.Equal(t, "10235000000000000000000000000000000", daMaxBI.String())
  569. daMax1Hex, err := hex.DecodeString("FFFE")
  570. require.NoError(t, err)
  571. daMax1F16 := common.Float16(binary.BigEndian.Uint16(daMax1Hex))
  572. daMax1BI := daMax1F16.BigInt()
  573. assert.Equal(t, "10225000000000000000000000000000000", daMax1BI.String())
  574. l1Txs := []common.L1Tx{
  575. {
  576. FromIdx: 0,
  577. DepositAmount: daMaxBI,
  578. Amount: big.NewInt(0),
  579. TokenID: 1,
  580. FromBJJ: users[0].BJJ.Public().Compress(),
  581. FromEthAddr: users[0].Addr,
  582. ToIdx: 0,
  583. Type: common.TxTypeCreateAccountDeposit,
  584. UserOrigin: true,
  585. },
  586. {
  587. FromIdx: 0,
  588. DepositAmount: daMax1BI,
  589. Amount: big.NewInt(0),
  590. TokenID: 1,
  591. FromBJJ: users[1].BJJ.Public().Compress(),
  592. FromEthAddr: users[1].Addr,
  593. ToIdx: 0,
  594. Type: common.TxTypeCreateAccountDeposit,
  595. UserOrigin: true,
  596. },
  597. }
  598. chainID := uint16(0)
  599. config := Config{
  600. NLevels: uint32(nLevels),
  601. MaxTx: 3,
  602. MaxL1Tx: 2,
  603. MaxFeeTx: 2,
  604. ChainID: chainID,
  605. }
  606. tp := NewTxProcessor(sdb, config)
  607. _, err = tp.ProcessTxs(nil, l1Txs, nil, nil)
  608. require.NoError(t, err)
  609. // check balances
  610. acc, err := sdb.GetAccount(common.Idx(256))
  611. require.NoError(t, err)
  612. assert.Equal(t, daMaxBI, acc.Balance)
  613. acc, err = sdb.GetAccount(common.Idx(257))
  614. require.NoError(t, err)
  615. assert.Equal(t, daMax1BI, acc.Balance)
  616. }
  617. func initTestMultipleCoordIdxForTokenID(t *testing.T) (*TxProcessor, *til.Context, []common.BlockData) {
  618. dir, err := ioutil.TempDir("", "tmpdb")
  619. require.NoError(t, err)
  620. defer assert.NoError(t, os.RemoveAll(dir))
  621. sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, 32)
  622. assert.NoError(t, err)
  623. chainID := uint16(1)
  624. // generate test transactions from test.SetBlockchain0 code
  625. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  626. set := `
  627. Type: Blockchain
  628. CreateAccountDeposit(0) A: 200
  629. > batchL1 // freeze L1User{1}
  630. CreateAccountCoordinator(0) Coord
  631. CreateAccountCoordinator(0) B
  632. Transfer(0) A-B: 100 (126)
  633. > batchL1 // forge L1User{1}, forge L1Coord{4}, forge L2{2}
  634. > block
  635. `
  636. blocks, err := tc.GenerateBlocks(set)
  637. require.NoError(t, err)
  638. config := Config{
  639. NLevels: 32,
  640. MaxFeeTx: 64,
  641. MaxTx: 512,
  642. MaxL1Tx: 16,
  643. ChainID: chainID,
  644. }
  645. tp := NewTxProcessor(sdb, config)
  646. // batch1
  647. _, err = tp.ProcessTxs(nil, nil, nil, nil) // to simulate the first batch from the Til set
  648. require.NoError(t, err)
  649. return tp, tc, blocks
  650. }
  651. func TestMultipleCoordIdxForTokenID(t *testing.T) {
  652. // Check that ProcessTxs always uses the first occurrence of the
  653. // CoordIdx for each TokenID
  654. coordIdxs := []common.Idx{257, 257, 257}
  655. tp, tc, blocks := initTestMultipleCoordIdxForTokenID(t)
  656. l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  657. l1CoordTxs := blocks[0].Rollup.Batches[1].L1CoordinatorTxs
  658. l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
  659. l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  660. _, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
  661. require.NoError(t, err)
  662. checkBalanceByIdx(t, tp.s, 256, "90") // A
  663. checkBalanceByIdx(t, tp.s, 257, "10") // Coord0
  664. checkBalanceByIdx(t, tp.s, 258, "100") // B
  665. checkBalanceByIdx(t, tp.s, 259, "0") // Coord0
  666. // reset StateDB values
  667. coordIdxs = []common.Idx{259, 257}
  668. tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
  669. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  670. l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
  671. l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
  672. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  673. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
  674. require.NoError(t, err)
  675. checkBalanceByIdx(t, tp.s, 256, "90") // A
  676. checkBalanceByIdx(t, tp.s, 257, "0") // Coord0
  677. checkBalanceByIdx(t, tp.s, 258, "100") // B
  678. checkBalanceByIdx(t, tp.s, 259, "10") // Coord0
  679. // reset StateDB values
  680. coordIdxs = []common.Idx{257, 259}
  681. tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
  682. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  683. l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
  684. l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
  685. l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
  686. _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
  687. require.NoError(t, err)
  688. checkBalanceByIdx(t, tp.s, 256, "90") // A
  689. checkBalanceByIdx(t, tp.s, 257, "10") // Coord0
  690. checkBalanceByIdx(t, tp.s, 258, "100") // B
  691. checkBalanceByIdx(t, tp.s, 259, "0") // Coord0
  692. }
  693. func TestTwoExits(t *testing.T) {
  694. // In the first part we generate a batch with two force exits for the
  695. // same account of 20 each. The txprocessor output should be a single
  696. // exitInfo with balance of 40.
  697. dir, err := ioutil.TempDir("", "tmpdb")
  698. require.NoError(t, err)
  699. defer assert.NoError(t, os.RemoveAll(dir))
  700. sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeSynchronizer, 32)
  701. assert.NoError(t, err)
  702. chainID := uint16(1)
  703. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  704. // Two exits for the same account. The tx processor should output a
  705. // single exit with the accumulated exit balance
  706. set := `
  707. Type: Blockchain
  708. CreateAccountDeposit(0) A: 100
  709. > batchL1 // freeze L1User{1}
  710. > batchL1 // forge L1User{1}
  711. ForceExit(0) A: 20
  712. ForceExit(0) A: 20
  713. > batchL1 // freeze L1User{2}
  714. > batchL1 // forge L1User{2}
  715. > block
  716. `
  717. blocks, err := tc.GenerateBlocks(set)
  718. require.NoError(t, err)
  719. err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
  720. require.NoError(t, err)
  721. err = tc.FillBlocksForgedL1UserTxs(blocks)
  722. require.NoError(t, err)
  723. // Sanity check
  724. require.Equal(t, 1, len(blocks[0].Rollup.Batches[1].L1UserTxs))
  725. require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
  726. config := Config{
  727. NLevels: 32,
  728. MaxFeeTx: 64,
  729. MaxTx: 512,
  730. MaxL1Tx: 16,
  731. ChainID: chainID,
  732. }
  733. tp := NewTxProcessor(sdb, config)
  734. ptOuts := []*ProcessTxOutput{}
  735. for _, block := range blocks {
  736. for _, batch := range block.Rollup.Batches {
  737. ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
  738. require.NoError(t, err)
  739. ptOuts = append(ptOuts, ptOut)
  740. }
  741. }
  742. assert.Equal(t, 1, len(ptOuts[3].ExitInfos))
  743. assert.Equal(t, big.NewInt(40), ptOuts[3].ExitInfos[0].Balance)
  744. acc, err := sdb.GetAccount(256)
  745. require.NoError(t, err)
  746. assert.Equal(t, big.NewInt(60), acc.Balance)
  747. // In the second part we start a fresh statedb and generate a batch
  748. // with one force exit for the same account as before. The txprocessor
  749. // output should be a single exitInfo with balance of 40, and the exit
  750. // merkle tree proof should be equal to the previous one.
  751. dir2, err := ioutil.TempDir("", "tmpdb")
  752. require.NoError(t, err)
  753. defer assert.NoError(t, os.RemoveAll(dir2))
  754. sdb2, err := statedb.NewStateDB(dir2, 128, statedb.TypeSynchronizer, 32)
  755. assert.NoError(t, err)
  756. tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  757. // Single exit with balance of both exits in previous set. The exit
  758. // root should match.
  759. set2 := `
  760. Type: Blockchain
  761. CreateAccountDeposit(0) A: 100
  762. > batchL1 // freeze L1User{1}
  763. > batchL1 // forge L1User{1}
  764. ForceExit(0) A: 40
  765. > batchL1 // freeze L1User{2}
  766. > batchL1 // forge L1User{2}
  767. > block
  768. `
  769. blocks, err = tc.GenerateBlocks(set2)
  770. require.NoError(t, err)
  771. err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
  772. require.NoError(t, err)
  773. err = tc.FillBlocksForgedL1UserTxs(blocks)
  774. require.NoError(t, err)
  775. tp = NewTxProcessor(sdb2, config)
  776. ptOuts2 := []*ProcessTxOutput{}
  777. for _, block := range blocks {
  778. for _, batch := range block.Rollup.Batches {
  779. ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
  780. require.NoError(t, err)
  781. ptOuts2 = append(ptOuts2, ptOut)
  782. }
  783. }
  784. assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts2[3].ExitInfos[0].MerkleProof)
  785. }