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