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.

858 lines
30 KiB

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