hermez-node/test/zkproof/flows_test.go
test/zkproof/flows_test.goRaw
1package zkproof
2
3import (
4 "io/ioutil"
5 "os"
6 "strconv"
7 "testing"
8 "time"
9
10 ethCommon "github.com/ethereum/go-ethereum/common"
11 ethCrypto "github.com/ethereum/go-ethereum/crypto"
12 "github.com/hermeznetwork/hermez-node/batchbuilder"
13 "github.com/hermeznetwork/hermez-node/common"
14 dbUtils "github.com/hermeznetwork/hermez-node/db"
15 "github.com/hermeznetwork/hermez-node/db/historydb"
16 "github.com/hermeznetwork/hermez-node/db/l2db"
17 "github.com/hermeznetwork/hermez-node/db/statedb"
18 "github.com/hermeznetwork/hermez-node/log"
19 "github.com/hermeznetwork/hermez-node/test"
20 "github.com/hermeznetwork/hermez-node/test/til"
21 "github.com/hermeznetwork/hermez-node/test/txsets"
22 "github.com/hermeznetwork/hermez-node/txselector"
23 "github.com/jmoiron/sqlx"
24 "github.com/stretchr/testify/assert"
25 "github.com/stretchr/testify/require"
26)
27
28func addTokens(t *testing.T, tc *til.Context, db *sqlx.DB) {
29 var tokens []common.Token
30 for i := 0; i < int(tc.LastRegisteredTokenID); i++ {
31 tokens = append(tokens, common.Token{
32 TokenID: common.TokenID(i + 1),
33 EthBlockNum: 1,
34 EthAddr: ethCommon.BytesToAddress([]byte{byte(i + 1)}),
35 Name: strconv.Itoa(i),
36 Symbol: strconv.Itoa(i),
37 Decimals: 18,
38 })
39 }
40
41 hdb := historydb.NewHistoryDB(db, db, nil)
42 assert.NoError(t, hdb.AddBlock(&common.Block{
43 Num: 1,
44 }))
45 assert.NoError(t, hdb.AddTokens(tokens))
46}
47
48func addL2Txs(t *testing.T, l2DB *l2db.L2DB, poolL2Txs []common.PoolL2Tx) {
49 for i := 0; i < len(poolL2Txs); i++ {
50 err := l2DB.AddTxTest(&poolL2Txs[i])
51 if err != nil {
52 log.Error(err)
53 }
54 require.NoError(t, err)
55 }
56}
57
58func addAccCreationAuth(t *testing.T, tc *til.Context, l2DB *l2db.L2DB, chainID uint16,
59 hermezContractAddr ethCommon.Address, username string) []byte {
60 user := tc.Users[username]
61 auth := &common.AccountCreationAuth{
62 EthAddr: user.Addr,
63 BJJ: user.BJJ.Public().Compress(),
64 }
65 err := auth.Sign(func(hash []byte) ([]byte, error) {
66 return ethCrypto.Sign(hash, user.EthSk)
67 }, chainID, hermezContractAddr)
68 assert.NoError(t, err)
69
70 err = l2DB.AddAccountCreationAuth(auth)
71 assert.NoError(t, err)
72 return auth.Signature
73}
74
75func initTxSelector(t *testing.T, chainID uint16, hermezContractAddr ethCommon.Address,
76 coordUser *til.User) (*txselector.TxSelector, *l2db.L2DB, *statedb.StateDB) {
77 pass := os.Getenv("POSTGRES_PASS")
78 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
79 require.NoError(t, err)
80 l2DB := l2db.NewL2DB(db, db, 10, 100, 0.0, 24*time.Hour, nil)
81
82 dir, err := ioutil.TempDir("", "tmpSyncDB")
83 require.NoError(t, err)
84 defer assert.NoError(t, os.RemoveAll(dir))
85 syncStateDB, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
86 Type: statedb.TypeSynchronizer, NLevels: 0})
87 require.NoError(t, err)
88
89 txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
90 require.NoError(t, err)
91 defer assert.NoError(t, os.RemoveAll(dir))
92
93 // use Til Coord keys for tests compatibility
94 coordAccount := &txselector.CoordAccount{
95 Addr: coordUser.Addr,
96 BJJ: coordUser.BJJ.Public().Compress(),
97 AccountCreationAuth: nil,
98 }
99 auth := common.AccountCreationAuth{
100 EthAddr: coordUser.Addr,
101 BJJ: coordUser.BJJ.Public().Compress(),
102 }
103 err = auth.Sign(func(hash []byte) ([]byte, error) {
104 return ethCrypto.Sign(hash, coordUser.EthSk)
105 }, chainID, hermezContractAddr)
106 assert.NoError(t, err)
107 coordAccount.AccountCreationAuth = auth.Signature
108
109 txsel, err := txselector.NewTxSelector(coordAccount, txselDir, syncStateDB, l2DB)
110 require.NoError(t, err)
111
112 test.WipeDB(l2DB.DB())
113
114 return txsel, l2DB, syncStateDB
115}
116
117func TestTxSelectorBatchBuilderZKInputsMinimumFlow0(t *testing.T) {
118 tc := til.NewContext(ChainID, common.RollupConstMaxL1UserTx)
119 // generate test transactions, the L1CoordinatorTxs generated by Til
120 // will be ignored at this test, as will be the TxSelector who
121 // generates them when needed
122 blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
123 require.NoError(t, err)
124
125 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
126 txsel, l2DBTxSel, syncStateDB := initTxSelector(t, ChainID, hermezContractAddr, tc.Users["Coord"])
127
128 bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB")
129 require.NoError(t, err)
130 bb, err := batchbuilder.NewBatchBuilder(bbDir, syncStateDB, 0, NLevels)
131 require.NoError(t, err)
132
133 // restart nonces of TilContext, as will be set by generating directly
134 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
135 tc.RestartNonces()
136
137 // add tokens to HistoryDB to avoid breaking FK constrains
138 addTokens(t, tc, l2DBTxSel.DB())
139
140 selectionConfig := &txselector.SelectionConfig{
141 MaxL1UserTxs: 100, // TODO
142 TxProcessorConfig: txprocConfig,
143 }
144 configBatch := &batchbuilder.ConfigBatch{
145 // ForgerAddress:
146 TxProcessorConfig: txprocConfig,
147 }
148
149 // loop over the first 6 batches
150 expectedRoots := []string{"0", "0",
151 "13644148972047617726265275926674266298636745191961029124811988256139761111521",
152 "12433441613247342495680642890662773367605896324555599297255745922589338651261",
153 "12433441613247342495680642890662773367605896324555599297255745922589338651261",
154 "4191361650490017591061467288209836928064232431729236465872209988325272262963"}
155 for i := 0; i < 6; i++ {
156 log.Debugf("block:0 batch:%d", i+1)
157 var l1UserTxs []common.L1Tx
158 if blocks[0].Rollup.Batches[i].Batch.ForgeL1TxsNum != nil {
159 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[i].Batch.ForgeL1TxsNum])
160 }
161 // TxSelector select the transactions for the next Batch
162 coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err :=
163 txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
164 require.NoError(t, err)
165 // BatchBuilder build Batch
166 zki, err := bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
167 require.NoError(t, err)
168 assert.Equal(t, expectedRoots[i], bb.LocalStateDB().MT.Root().BigInt().String())
169 sendProofAndCheckResp(t, zki)
170 }
171
172 log.Debug("block:0 batch:7")
173 // simulate the PoolL2Txs of the batch6
174 batchPoolL2 := `
175 Type: PoolL2
176 PoolTransferToEthAddr(1) A-B: 200 (126)
177 PoolTransferToEthAddr(0) B-C: 100 (126)`
178 l2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
179 require.NoError(t, err)
180 // add AccountCreationAuths that will be used at the next batch
181 _ = addAccCreationAuth(t, tc, l2DBTxSel, ChainID, hermezContractAddr, "B")
182 _ = addAccCreationAuth(t, tc, l2DBTxSel, ChainID, hermezContractAddr, "C")
183 addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
184 l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
185 // TxSelector select the transactions for the next Batch
186 coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
187 txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
188 require.NoError(t, err)
189 // BatchBuilder build Batch
190 zki, err := bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
191 require.NoError(t, err)
192 assert.Equal(t,
193 "7614010373759339299470010949167613050707822522530721724565424494781010548240",
194 bb.LocalStateDB().MT.Root().BigInt().String())
195 sendProofAndCheckResp(t, zki)
196 err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
197 txsel.LocalAccountsDB().CurrentBatch())
198 require.NoError(t, err)
199 err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
200 require.NoError(t, err)
201
202 log.Debug("block:0 batch:8")
203 // simulate the PoolL2Txs of the batch8
204 batchPoolL2 = `
205 Type: PoolL2
206 PoolTransfer(0) A-B: 100 (126)
207 PoolTransfer(0) C-A: 50 (126)
208 PoolTransfer(1) B-C: 100 (126)
209 PoolExit(0) A: 100 (126)`
210 l2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
211 require.NoError(t, err)
212 addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
213 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
214 // TxSelector select the transactions for the next Batch
215 coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
216 txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
217 require.NoError(t, err)
218 // BatchBuilder build Batch
219 zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
220 require.NoError(t, err)
221 assert.Equal(t,
222 "21231789250434471575486264439945776732824482207853465397552873521865656677689",
223 bb.LocalStateDB().MT.Root().BigInt().String())
224 sendProofAndCheckResp(t, zki)
225 err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(l2Txs),
226 txsel.LocalAccountsDB().CurrentBatch())
227 require.NoError(t, err)
228 err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
229 require.NoError(t, err)
230
231 log.Debug("(batch9) block:1 batch:1")
232 // simulate the PoolL2Txs of the batch9
233 batchPoolL2 = `
234 Type: PoolL2
235 PoolTransfer(0) D-A: 300 (126)
236 PoolTransfer(0) B-D: 100 (126)`
237 l2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
238 require.NoError(t, err)
239 addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
240 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
241 // TxSelector select the transactions for the next Batch
242 coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
243 txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
244 require.NoError(t, err)
245 // BatchBuilder build Batch
246 zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
247 require.NoError(t, err)
248 assert.Equal(t,
249 "11289313644810782435120113035387729451095637380468777086895109386127538554246",
250 bb.LocalStateDB().MT.Root().BigInt().String())
251 sendProofAndCheckResp(t, zki)
252 err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(l2Txs),
253 txsel.LocalAccountsDB().CurrentBatch())
254 require.NoError(t, err)
255 err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
256 require.NoError(t, err)
257
258 log.Debug("(batch10) block:1 batch:2")
259 l2Txs = []common.PoolL2Tx{}
260 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[1].Batch.ForgeL1TxsNum])
261 // TxSelector select the transactions for the next Batch
262 coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
263 txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
264 require.NoError(t, err)
265 // BatchBuilder build Batch
266 zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
267 require.NoError(t, err)
268 // same root as previous batch, as the L1CoordinatorTxs created by the
269 // Til set is not created by the TxSelector in this test
270 assert.Equal(t,
271 "11289313644810782435120113035387729451095637380468777086895109386127538554246",
272 bb.LocalStateDB().MT.Root().BigInt().String())
273 sendProofAndCheckResp(t, zki)
274 err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(l2Txs),
275 txsel.LocalAccountsDB().CurrentBatch())
276 require.NoError(t, err)
277 err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
278 require.NoError(t, err)
279}
280
281// TestZKInputsExitWithFee0 checks the case where there is a PoolTxs of type
282// Exit with fee 0 for a TokenID that the Coordinator does not have it
283// registered yet
284func TestZKInputsExitWithFee0(t *testing.T) {
285 tc := til.NewContext(ChainID, common.RollupConstMaxL1UserTx)
286
287 var set = `
288 Type: Blockchain
289 AddToken(1)
290
291 CreateAccountDeposit(1) A: 1000
292 CreateAccountDeposit(1) B: 1000
293 CreateAccountDeposit(1) C: 1000
294 > batchL1
295 > batchL1
296
297 CreateAccountCoordinator(1) Coord
298 > batch
299 > block
300 `
301 blocks, err := tc.GenerateBlocks(set)
302 require.NoError(t, err)
303
304 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
305 txsel, l2DBTxSel, syncStateDB := initTxSelector(t, ChainID, hermezContractAddr, tc.Users["Coord"])
306
307 bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB")
308 require.NoError(t, err)
309 bb, err := batchbuilder.NewBatchBuilder(bbDir, syncStateDB, 0, NLevels)
310 require.NoError(t, err)
311
312 // restart nonces of TilContext, as will be set by generating directly
313 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
314 tc.RestartNonces()
315 // add tokens to HistoryDB to avoid breaking FK constrains
316 addTokens(t, tc, l2DBTxSel.DB())
317
318 selectionConfig := &txselector.SelectionConfig{
319 MaxL1UserTxs: 100,
320 TxProcessorConfig: txprocConfig,
321 }
322 configBatch := &batchbuilder.ConfigBatch{
323 TxProcessorConfig: txprocConfig,
324 }
325
326 // batch2
327 // TxSelector select the transactions for the next Batch
328 l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
329 coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err :=
330 txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
331 require.NoError(t, err)
332 // BatchBuilder build Batch
333 zki, err := bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
334 require.NoError(t, err)
335 assert.Equal(t,
336 "8737171572459172806192626402462788826264011087579491137542380589998149683116",
337 bb.LocalStateDB().MT.Root().BigInt().String())
338 h, err := zki.HashGlobalData()
339 require.NoError(t, err)
340 assert.Equal(t,
341 "18608843755023673022528019960628191162333429206359207449879743919826610006009",
342 h.String())
343 sendProofAndCheckResp(t, zki)
344
345 // batch3
346 batchPoolL2 := `
347 Type: PoolL2
348 PoolExit(1) A: 100 (0)`
349 l2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
350 require.NoError(t, err)
351 addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
352 coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
353 txsel.GetL1L2TxSelection(selectionConfig, nil)
354 require.NoError(t, err)
355 assert.Equal(t, 1, len(coordIdxs))
356 assert.Equal(t, 0, len(oL1UserTxs))
357 assert.Equal(t, 1, len(oL1CoordTxs))
358 assert.Equal(t, 1, len(oL2Txs))
359 assert.Equal(t, 0, len(discardedL2Txs))
360 // BatchBuilder build Batch
361 zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
362 require.NoError(t, err)
363 assert.Equal(t,
364 "18306761925365215381387147754881756804475668085493847010988306480531520370130",
365 bb.LocalStateDB().MT.Root().BigInt().String())
366 h, err = zki.HashGlobalData()
367 require.NoError(t, err)
368 assert.Equal(t,
369 "6651837443119278772088559395433504719862425648816904171510845286897104469889",
370 h.String())
371 assert.Equal(t, common.EthAddrToBigInt(tc.Users["Coord"].Addr), zki.EthAddr3[0])
372 assert.Equal(t, "0", zki.EthAddr3[1].String())
373 sendProofAndCheckResp(t, zki)
374}