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
151func TestGeneratePoolL2Txs(t *testing.T) {
152 set := `
153 Type: Blockchain
154 RegisterToken(1)
155 RegisterToken(2)
156 RegisterToken(3)
157
158 CreateAccountDeposit(1) A: 10
159 CreateAccountDeposit(2) A: 20
160 CreateAccountDeposit(1) B: 5
161 CreateAccountDeposit(1) C: 5
162 CreateAccountDeposit(1) User0: 5
163 CreateAccountDeposit(1) User1: 0
164 CreateAccountDeposit(3) User0: 0
165 CreateAccountDeposit(3) User1: 5
166 CreateAccountDeposit(2) B: 5
167 CreateAccountDeposit(2) D: 0
168 > batchL1
169 > batchL1
170 `
171 tc := NewContext(eth.RollupConstMaxL1UserTx)
172 _, err := tc.GenerateBlocks(set)
173 require.Nil(t, err)
174 set = `
175 Type: PoolL2
176 PoolTransfer(1) A-B: 6 (1)
177 PoolTransfer(1) B-C: 3 (1)
178 PoolTransfer(1) C-A: 3 (1)
179 PoolTransfer(1) A-B: 1 (1)
180 PoolTransfer(2) A-B: 15 (1)
181 PoolTransfer(1) User0-User1: 15 (1)
182 PoolTransfer(3) User1-User0: 15 (1)
183 PoolTransfer(2) B-D: 3 (1)
184 PoolExit(1) A: 3
185 `
186 poolL2Txs, err := tc.GeneratePoolL2Txs(set)
187 require.Nil(t, err)
188 assert.Equal(t, 9, len(poolL2Txs))
189 assert.Equal(t, common.TxTypeTransfer, poolL2Txs[0].Type)
190 assert.Equal(t, common.TxTypeExit, poolL2Txs[8].Type)
191 assert.Equal(t, tc.Users["B"].Addr.Hex(), poolL2Txs[0].ToEthAddr.Hex())
192 assert.Equal(t, tc.Users["B"].BJJ.Public().String(), poolL2Txs[0].ToBJJ.String())
193 assert.Equal(t, tc.Users["User1"].Addr.Hex(), poolL2Txs[5].ToEthAddr.Hex())
194 assert.Equal(t, tc.Users["User1"].BJJ.Public().String(), poolL2Txs[5].ToBJJ.String())
195
196 assert.Equal(t, common.Nonce(1), poolL2Txs[0].Nonce)
197 assert.Equal(t, common.Nonce(2), poolL2Txs[3].Nonce)
198 assert.Equal(t, common.Nonce(3), poolL2Txs[8].Nonce)
199
200 // load another set in the same Context
201 set = `
202 Type: PoolL2
203 PoolTransfer(1) A-B: 6 (1)
204 PoolTransfer(1) B-C: 3 (1)
205 PoolTransfer(1) A-C: 3 (1)
206 `
207 poolL2Txs, err = tc.GeneratePoolL2Txs(set)
208 require.Nil(t, err)
209 assert.Equal(t, common.Nonce(4), poolL2Txs[0].Nonce)
210 assert.Equal(t, common.Nonce(2), poolL2Txs[1].Nonce)
211 assert.Equal(t, common.Nonce(5), poolL2Txs[2].Nonce)
212}
213
214func TestGenerateErrors(t *testing.T) {
215 // unregistered token
216 set := `Type: Blockchain
217 CreateAccountDeposit(1) A: 5
218 > batchL1
219 `
220 tc := NewContext(eth.RollupConstMaxL1UserTx)
221 _, err := tc.GenerateBlocks(set)
222 assert.Equal(t, "Line 2: Can not process CreateAccountDeposit: TokenID 1 not registered, last registered TokenID: 0", err.Error())
223
224 // ensure RegisterToken sequentiality and not using 0
225 set = `
226 Type: Blockchain
227 RegisterToken(0)
228 `
229 tc = NewContext(eth.RollupConstMaxL1UserTx)
230 _, err = tc.GenerateBlocks(set)
231 require.Equal(t, "Line 2: RegisterToken can not register TokenID 0", err.Error())
232
233 set = `
234 Type: Blockchain
235 RegisterToken(2)
236 `
237 tc = NewContext(eth.RollupConstMaxL1UserTx)
238 _, err = tc.GenerateBlocks(set)
239 require.Equal(t, "Line 2: RegisterToken TokenID should be sequential, expected TokenID: 1, defined TokenID: 2", err.Error())
240
241 set = `
242 Type: Blockchain
243 RegisterToken(1)
244 RegisterToken(2)
245 RegisterToken(3)
246 RegisterToken(5)
247 `
248 tc = NewContext(eth.RollupConstMaxL1UserTx)
249 _, err = tc.GenerateBlocks(set)
250 require.Equal(t, "Line 5: RegisterToken TokenID should be sequential, expected TokenID: 4, defined TokenID: 5", err.Error())
251
252 // check transactions when account is not created yet
253 set = `
254 Type: Blockchain
255 RegisterToken(1)
256 CreateAccountDeposit(1) A: 10
257 > batchL1
258 CreateAccountDeposit(1) B
259 Transfer(1) A-B: 6 (1)
260 > batch
261 `
262 tc = NewContext(eth.RollupConstMaxL1UserTx)
263 _, err = tc.GenerateBlocks(set)
264 require.Equal(t, "Line 5: CreateAccountDeposit(1)BTransfer(1) A-B: 6 (1)\n, err: Expected ':', found 'Transfer'", err.Error())
265 set = `
266 Type: Blockchain
267 RegisterToken(1)
268 CreateAccountDeposit(1) A: 10
269 > batchL1
270 CreateAccountDepositCoordinator(1) B
271 > batchL1
272 > batch
273 Transfer(1) A-B: 6 (1)
274 > batch
275 `
276 tc = NewContext(eth.RollupConstMaxL1UserTx)
277 _, err = tc.GenerateBlocks(set)
278 require.Nil(t, err)
279
280 // check nonces
281 set = `
282 Type: Blockchain
283 RegisterToken(1)
284 CreateAccountDeposit(1) A: 10
285 > batchL1
286 CreateAccountDepositCoordinator(1) B
287 > batchL1
288 Transfer(1) A-B: 6 (1)
289 Transfer(1) A-B: 6 (1) // on purpose this is moving more money that what it has in the account, Til should not fail
290 Transfer(1) B-A: 6 (1)
291 Exit(1) A: 3
292 > batch
293 `
294 tc = NewContext(eth.RollupConstMaxL1UserTx)
295 _, err = tc.GenerateBlocks(set)
296 require.Nil(t, err)
297 assert.Equal(t, common.Nonce(3), tc.Users["A"].Accounts[common.TokenID(1)].Nonce)
298 assert.Equal(t, common.Idx(256), tc.Users["A"].Accounts[common.TokenID(1)].Idx)
299 assert.Equal(t, common.Nonce(1), tc.Users["B"].Accounts[common.TokenID(1)].Nonce)
300 assert.Equal(t, common.Idx(257), tc.Users["B"].Accounts[common.TokenID(1)].Idx)
301}