arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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}