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.

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