hermez-node/test/til/txs_test.go
test/til/txs_test.goRaw
1package til
2
3import (
4 "math/big"
5 "testing"
6
7 "github.com/hermeznetwork/hermez-node/common"
8 "github.com/hermeznetwork/hermez-node/eth"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/require"
11)
12
13func TestGenerateBlocksNoBatches(t *testing.T) {
14 set := `
15 Type: Blockchain
16 AddToken(1)
17 AddToken(2)
18
19 CreateAccountDeposit(1) A: 11
20 CreateAccountDeposit(2) B: 22
21
22 > block
23 `
24 tc := NewContext(eth.RollupConstMaxL1UserTx)
25 blocks, err := tc.GenerateBlocks(set)
26 require.Nil(t, err)
27 assert.Equal(t, 1, len(blocks))
28 assert.Equal(t, 0, len(blocks[0].Batches))
29 assert.Equal(t, 2, len(blocks[0].AddedTokens))
30 assert.Equal(t, 2, len(blocks[0].L1UserTxs))
31}
32
33func TestGenerateBlocks(t *testing.T) {
34 set := `
35 Type: Blockchain
36 AddToken(1)
37 AddToken(2)
38 AddToken(3)
39
40 CreateAccountDeposit(1) A: 10
41 CreateAccountDeposit(2) A: 20
42 CreateAccountDeposit(1) B: 5
43 CreateAccountDeposit(1) C: 5
44 CreateAccountDeposit(1) D: 5
45
46 > batchL1 // batchNum = 1
47 > batchL1 // batchNum = 2
48
49 CreateAccountDepositTransfer(1) F-A: 15, 10
50
51 Transfer(1) A-B: 6 (1)
52 Transfer(1) B-D: 3 (1)
53 Transfer(1) A-D: 1 (1)
54
55 // set new batch
56 > batch // batchNum = 3
57 CreateAccountDepositCoordinator(1) E
58 CreateAccountDepositCoordinator(2) B
59
60 DepositTransfer(1) A-B: 15, 10
61 Transfer(1) C-A : 3 (1)
62 Transfer(2) A-B: 15 (1)
63 Transfer(1) A-E: 1 (1)
64
65 CreateAccountDeposit(1) User0: 20
66 CreateAccountDeposit(3) User1: 20
67 CreateAccountDepositCoordinator(1) User1
68 CreateAccountDepositCoordinator(3) User0
69 > batchL1 // batchNum = 4
70 Transfer(1) User0-User1: 15 (1)
71 Transfer(3) User1-User0: 15 (1)
72 Transfer(1) A-C: 1 (1)
73
74 > batchL1 // batchNum = 5
75
76 Transfer(1) User1-User0: 1 (1)
77
78 > block
79
80 // Exits
81 Transfer(1) A-B: 1 (1)
82 Exit(1) A: 5 (1)
83
84 > batch // batchNum = 6
85 > block
86
87 // this transaction should not be generated, as it's after last
88 // batch and last block
89 Transfer(1) User1-User0: 1 (1)
90 `
91 tc := NewContext(eth.RollupConstMaxL1UserTx)
92 blocks, err := tc.GenerateBlocks(set)
93 require.Nil(t, err)
94 assert.Equal(t, 2, len(blocks))
95 assert.Equal(t, 5, len(blocks[0].Batches))
96 assert.Equal(t, 1, len(blocks[1].Batches))
97 assert.Equal(t, 9, len(blocks[0].L1UserTxs))
98 assert.Equal(t, 4, len(blocks[0].Batches[3].L1CoordinatorTxs))
99 assert.Equal(t, 0, len(blocks[1].L1UserTxs))
100
101 // Check expected values generated by each line
102 // #0: Deposit(1) A: 10
103 tc.checkL1TxParams(t, blocks[0].L1UserTxs[0], common.TxTypeCreateAccountDeposit, 1, "A", "", big.NewInt(10), nil)
104 // #1: Deposit(2) A: 20
105 tc.checkL1TxParams(t, blocks[0].L1UserTxs[1], common.TxTypeCreateAccountDeposit, 2, "A", "", big.NewInt(20), nil)
106 // // #2: Deposit(1) A: 20
107 tc.checkL1TxParams(t, blocks[0].L1UserTxs[2], common.TxTypeCreateAccountDeposit, 1, "B", "", big.NewInt(5), nil)
108 // // #3: CreateAccountDeposit(1) C: 5
109 tc.checkL1TxParams(t, blocks[0].L1UserTxs[3], common.TxTypeCreateAccountDeposit, 1, "C", "", big.NewInt(5), nil)
110 // // #4: CreateAccountDeposit(1) D: 5
111 tc.checkL1TxParams(t, blocks[0].L1UserTxs[4], common.TxTypeCreateAccountDeposit, 1, "D", "", big.NewInt(5), nil)
112 // #5: Transfer(1) A-B: 6 (1)
113 tc.checkL2TxParams(t, blocks[0].Batches[2].L2Txs[0], common.TxTypeTransfer, 1, "A", "B", big.NewInt(6), common.BatchNum(3), common.Nonce(1))
114 // #6: Transfer(1) B-D: 3 (1)
115 tc.checkL2TxParams(t, blocks[0].Batches[2].L2Txs[1], common.TxTypeTransfer, 1, "B", "D", big.NewInt(3), common.BatchNum(3), common.Nonce(1))
116 // #7: Transfer(1) A-D: 1 (1)
117 tc.checkL2TxParams(t, blocks[0].Batches[2].L2Txs[2], common.TxTypeTransfer, 1, "A", "D", big.NewInt(1), common.BatchNum(3), common.Nonce(2))
118 // change of Batch
119 // #8: CreateAccountDepositTransfer(1) F-A: 15, 10 (3)
120 tc.checkL1TxParams(t, blocks[0].L1UserTxs[5], common.TxTypeCreateAccountDepositTransfer, 1, "F", "A", big.NewInt(15), big.NewInt(10))
121 // #9: DepositTransfer(1) A-B: 15, 10 (1)
122 tc.checkL1TxParams(t, blocks[0].L1UserTxs[6], common.TxTypeDepositTransfer, 1, "A", "B", big.NewInt(15), big.NewInt(10))
123 // #11: Transfer(1) C-A : 3 (1)
124 tc.checkL2TxParams(t, blocks[0].Batches[3].L2Txs[0], common.TxTypeTransfer, 1, "C", "A", big.NewInt(3), common.BatchNum(4), common.Nonce(1))
125 // #12: Transfer(2) A-B: 15 (1)
126 tc.checkL2TxParams(t, blocks[0].Batches[3].L2Txs[1], common.TxTypeTransfer, 2, "A", "B", big.NewInt(15), common.BatchNum(4), common.Nonce(1))
127 // #13: Deposit(1) User0: 20
128 tc.checkL1TxParams(t, blocks[0].L1UserTxs[7], common.TxTypeCreateAccountDeposit, 1, "User0", "", big.NewInt(20), nil)
129 // // #14: Deposit(3) User1: 20
130 tc.checkL1TxParams(t, blocks[0].L1UserTxs[8], common.TxTypeCreateAccountDeposit, 3, "User1", "", big.NewInt(20), nil)
131 // #15: Transfer(1) User0-User1: 15 (1)
132 tc.checkL2TxParams(t, blocks[0].Batches[4].L2Txs[0], common.TxTypeTransfer, 1, "User0", "User1", big.NewInt(15), common.BatchNum(5), common.Nonce(1))
133 // #16: Transfer(3) User1-User0: 15 (1)
134 tc.checkL2TxParams(t, blocks[0].Batches[4].L2Txs[1], common.TxTypeTransfer, 3, "User1", "User0", big.NewInt(15), common.BatchNum(5), common.Nonce(1))
135 // #17: Transfer(1) A-C: 1 (1)
136 tc.checkL2TxParams(t, blocks[0].Batches[4].L2Txs[2], common.TxTypeTransfer, 1, "A", "C", big.NewInt(1), common.BatchNum(5), common.Nonce(4))
137 // change of Batch
138 // #18: Transfer(1) User1-User0: 1 (1)
139 tc.checkL2TxParams(t, blocks[1].Batches[0].L2Txs[0], common.TxTypeTransfer, 1, "User1", "User0", big.NewInt(1), common.BatchNum(6), common.Nonce(1))
140 // change of Block (implies also a change of batch)
141 // #19: Transfer(1) A-B: 1 (1)
142 tc.checkL2TxParams(t, blocks[1].Batches[0].L2Txs[1], common.TxTypeTransfer, 1, "A", "B", big.NewInt(1), common.BatchNum(6), common.Nonce(5))
143}
144
145func (tc *Context) checkL1TxParams(t *testing.T, tx common.L1Tx, typ common.TxType, tokenID common.TokenID, from, to string, loadAmount, amount *big.Int) {
146 assert.Equal(t, typ, tx.Type)
147 if tx.FromIdx != common.Idx(0) {
148 assert.Equal(t, tc.Users[from].Accounts[tokenID].Idx, tx.FromIdx)
149 }
150 assert.Equal(t, tc.Users[from].Addr.Hex(), tx.FromEthAddr.Hex())
151 assert.Equal(t, tc.Users[from].BJJ.Public(), tx.FromBJJ)
152 if tx.ToIdx != common.Idx(0) {
153 assert.Equal(t, tc.Users[to].Accounts[tokenID].Idx, tx.ToIdx)
154 }
155 if loadAmount != nil {
156 assert.Equal(t, loadAmount, tx.LoadAmount)
157 }
158 if amount != nil {
159 assert.Equal(t, amount, tx.Amount)
160 }
161}
162
163func (tc *Context) checkL2TxParams(t *testing.T, tx common.L2Tx, typ common.TxType, tokenID common.TokenID, from, to string, amount *big.Int, batchNum common.BatchNum, nonce common.Nonce) {
164 assert.Equal(t, typ, tx.Type)
165 assert.Equal(t, tc.Users[from].Accounts[tokenID].Idx, tx.FromIdx)
166 if tx.Type != common.TxTypeExit {
167 assert.Equal(t, tc.Users[to].Accounts[tokenID].Idx, tx.ToIdx)
168 }
169 if amount != nil {
170 assert.Equal(t, amount, tx.Amount)
171 }
172 assert.Equal(t, batchNum, tx.BatchNum)
173 assert.Equal(t, nonce, tx.Nonce)
174}
175
176func TestGeneratePoolL2Txs(t *testing.T) {
177 set := `
178 Type: Blockchain
179 AddToken(1)
180 AddToken(2)
181 AddToken(3)
182
183 CreateAccountDeposit(1) A: 10
184 CreateAccountDeposit(2) A: 20
185 CreateAccountDeposit(1) B: 5
186 CreateAccountDeposit(1) C: 5
187 CreateAccountDeposit(1) User0: 5
188 CreateAccountDeposit(1) User1: 0
189 CreateAccountDeposit(3) User0: 0
190 CreateAccountDeposit(3) User1: 5
191 CreateAccountDeposit(2) B: 5
192 CreateAccountDeposit(2) D: 0
193 > batchL1
194 > batchL1
195 `
196 tc := NewContext(eth.RollupConstMaxL1UserTx)
197 _, err := tc.GenerateBlocks(set)
198 require.Nil(t, err)
199 set = `
200 Type: PoolL2
201 PoolTransfer(1) A-B: 6 (1)
202 PoolTransfer(1) B-C: 3 (1)
203 PoolTransfer(1) C-A: 3 (1)
204 PoolTransfer(1) A-B: 1 (1)
205 PoolTransfer(2) A-B: 15 (1)
206 PoolTransfer(1) User0-User1: 15 (1)
207 PoolTransfer(3) User1-User0: 15 (1)
208 PoolTransfer(2) B-D: 3 (1)
209 PoolExit(1) A: 3 (1)
210 PoolTransferToEthAddr(1) A-B: 1 (1)
211 PoolTransferToBJJ(1) A-B: 1 (1)
212 `
213 poolL2Txs, err := tc.GeneratePoolL2Txs(set)
214 require.Nil(t, err)
215 assert.Equal(t, 11, len(poolL2Txs))
216 assert.Equal(t, common.TxTypeTransfer, poolL2Txs[0].Type)
217 assert.Equal(t, common.TxTypeExit, poolL2Txs[8].Type)
218 assert.Equal(t, tc.Users["B"].Addr.Hex(), poolL2Txs[0].ToEthAddr.Hex())
219 assert.Equal(t, tc.Users["B"].BJJ.Public().String(), poolL2Txs[0].ToBJJ.String())
220 assert.Equal(t, tc.Users["User1"].Addr.Hex(), poolL2Txs[5].ToEthAddr.Hex())
221 assert.Equal(t, tc.Users["User1"].BJJ.Public().String(), poolL2Txs[5].ToBJJ.String())
222
223 assert.Equal(t, common.Nonce(1), poolL2Txs[0].Nonce)
224 assert.Equal(t, common.Nonce(2), poolL2Txs[3].Nonce)
225 assert.Equal(t, common.Nonce(3), poolL2Txs[8].Nonce)
226
227 assert.Equal(t, tc.Users["B"].Addr.Hex(), poolL2Txs[9].ToEthAddr.Hex())
228 assert.Nil(t, poolL2Txs[9].ToBJJ)
229 assert.Equal(t, common.TxTypeTransferToEthAddr, poolL2Txs[9].Type)
230 assert.Equal(t, common.FFAddr, poolL2Txs[10].ToEthAddr)
231 assert.Equal(t, tc.Users["B"].BJJ.Public().String(), poolL2Txs[10].ToBJJ.String())
232 assert.Equal(t, common.TxTypeTransferToBJJ, poolL2Txs[10].Type)
233
234 // load another set in the same Context
235 set = `
236 Type: PoolL2
237 PoolTransfer(1) A-B: 6 (1)
238 PoolTransfer(1) B-C: 3 (1)
239 PoolTransfer(1) A-C: 3 (1)
240 `
241 poolL2Txs, err = tc.GeneratePoolL2Txs(set)
242 require.Nil(t, err)
243 assert.Equal(t, common.Nonce(6), poolL2Txs[0].Nonce)
244 assert.Equal(t, common.Nonce(2), poolL2Txs[1].Nonce)
245 assert.Equal(t, common.Nonce(7), poolL2Txs[2].Nonce)
246
247 // check that a PoolL2Tx can be done to a non existing ToIdx
248 set = `
249 Type: Blockchain
250 AddToken(1)
251 CreateAccountDeposit(1) A: 10
252 > batchL1
253 > batchL1
254 > block
255 `
256 tc = NewContext(eth.RollupConstMaxL1UserTx)
257 _, err = tc.GenerateBlocks(set)
258 require.Nil(t, err)
259 set = `
260 Type: PoolL2
261 PoolTransferToEthAddr(1) A-B: 3 (1)
262 PoolTransferToBJJ(1) A-C: 3 (1)
263 `
264 _, err = tc.GeneratePoolL2Txs(set)
265 require.Nil(t, err)
266 // expect error, as FromIdx=B is still not created for TokenID=1
267 set = `
268 Type: PoolL2
269 PoolTransferToEthAddr(1) B-A: 3 (1)
270 PoolTransferToBJJ(1) B-A: 3 (1)
271 `
272 _, err = tc.GeneratePoolL2Txs(set)
273 require.NotNil(t, err)
274}
275
276func TestGenerateErrors(t *testing.T) {
277 // unregistered token
278 set := `Type: Blockchain
279 CreateAccountDeposit(1) A: 5
280 > batchL1
281 `
282 tc := NewContext(eth.RollupConstMaxL1UserTx)
283 _, err := tc.GenerateBlocks(set)
284 assert.Equal(t, "Line 2: Can not process CreateAccountDeposit: TokenID 1 not registered, last registered TokenID: 0", err.Error())
285
286 // ensure AddToken sequentiality and not using 0
287 set = `
288 Type: Blockchain
289 AddToken(0)
290 `
291 tc = NewContext(eth.RollupConstMaxL1UserTx)
292 _, err = tc.GenerateBlocks(set)
293 require.Equal(t, "Line 2: AddToken can not register TokenID 0", err.Error())
294
295 set = `
296 Type: Blockchain
297 AddToken(2)
298 `
299 tc = NewContext(eth.RollupConstMaxL1UserTx)
300 _, err = tc.GenerateBlocks(set)
301 require.Equal(t, "Line 2: AddToken TokenID should be sequential, expected TokenID: 1, defined TokenID: 2", err.Error())
302
303 set = `
304 Type: Blockchain
305 AddToken(1)
306 AddToken(2)
307 AddToken(3)
308 AddToken(5)
309 `
310 tc = NewContext(eth.RollupConstMaxL1UserTx)
311 _, err = tc.GenerateBlocks(set)
312 require.Equal(t, "Line 5: AddToken TokenID should be sequential, expected TokenID: 4, defined TokenID: 5", err.Error())
313
314 // check transactions when account is not created yet
315 set = `
316 Type: Blockchain
317 AddToken(1)
318 CreateAccountDeposit(1) A: 10
319 > batchL1
320 CreateAccountDeposit(1) B
321 Transfer(1) A-B: 6 (1)
322 > batch
323 `
324 tc = NewContext(eth.RollupConstMaxL1UserTx)
325 _, err = tc.GenerateBlocks(set)
326 require.Equal(t, "Line 5: CreateAccountDeposit(1)BTransfer(1) A-B: 6 (1)\n, err: Expected ':', found 'Transfer'", err.Error())
327 set = `
328 Type: Blockchain
329 AddToken(1)
330 CreateAccountDeposit(1) A: 10
331 > batchL1
332 CreateAccountDepositCoordinator(1) B
333 > batchL1
334 > batch
335 Transfer(1) A-B: 6 (1)
336 > batch
337 `
338 tc = NewContext(eth.RollupConstMaxL1UserTx)
339 _, err = tc.GenerateBlocks(set)
340 require.Nil(t, err)
341
342 // check nonces
343 set = `
344 Type: Blockchain
345 AddToken(1)
346 CreateAccountDeposit(1) A: 10
347 > batchL1
348 CreateAccountDepositCoordinator(1) B
349 > batchL1
350 Transfer(1) A-B: 6 (1)
351 Transfer(1) A-B: 6 (1) // on purpose this is moving more money that what it has in the account, Til should not fail
352 Transfer(1) B-A: 6 (1)
353 Exit(1) A: 3 (1)
354 > batch
355 `
356 tc = NewContext(eth.RollupConstMaxL1UserTx)
357 _, err = tc.GenerateBlocks(set)
358 require.Nil(t, err)
359 assert.Equal(t, common.Nonce(3), tc.Users["A"].Accounts[common.TokenID(1)].Nonce)
360 assert.Equal(t, common.Idx(256), tc.Users["A"].Accounts[common.TokenID(1)].Idx)
361 assert.Equal(t, common.Nonce(1), tc.Users["B"].Accounts[common.TokenID(1)].Nonce)
362 assert.Equal(t, common.Idx(257), tc.Users["B"].Accounts[common.TokenID(1)].Idx)
363}