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