arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/coordinator/pipeline_test.go
coordinator/pipeline_test.goRaw
  1package coordinator
  2
  3import (
  4	"context"
  5	"fmt"
  6	"io/ioutil"
  7	"math/big"
  8	"os"
  9	"testing"
 10
 11	ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
 12	ethCommon "github.com/ethereum/go-ethereum/common"
 13	"github.com/ethereum/go-ethereum/crypto"
 14	"github.com/ethereum/go-ethereum/ethclient"
 15	"github.com/hermeznetwork/hermez-node/common"
 16	"github.com/hermeznetwork/hermez-node/db/historydb"
 17	"github.com/hermeznetwork/hermez-node/db/statedb"
 18	"github.com/hermeznetwork/hermez-node/eth"
 19	"github.com/hermeznetwork/hermez-node/prover"
 20	"github.com/hermeznetwork/hermez-node/synchronizer"
 21	"github.com/hermeznetwork/hermez-node/test"
 22	"github.com/hermeznetwork/hermez-node/test/til"
 23	"github.com/iden3/go-merkletree"
 24	"github.com/stretchr/testify/assert"
 25	"github.com/stretchr/testify/require"
 26)
 27
 28func TestPipelineShouldL1L2Batch(t *testing.T) {
 29	ethClientSetup := test.NewClientSetupExample()
 30	ethClientSetup.ChainID = big.NewInt(int64(chainID))
 31
 32	var timer timer
 33	ctx := context.Background()
 34	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
 35	modules := newTestModules(t)
 36	var stats synchronizer.Stats
 37	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
 38	pipeline, err := coord.newPipeline(ctx)
 39	require.NoError(t, err)
 40	pipeline.vars = coord.vars
 41
 42	// Check that the parameters are the ones we expect and use in this test
 43	require.Equal(t, 0.5, pipeline.cfg.L1BatchTimeoutPerc)
 44	require.Equal(t, int64(10), ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout)
 45	l1BatchTimeoutPerc := pipeline.cfg.L1BatchTimeoutPerc
 46	l1BatchTimeout := ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout
 47
 48	startBlock := int64(100)
 49	// Empty batchInfo to pass to shouldL1L2Batch() which sets debug information
 50	batchInfo := BatchInfo{}
 51
 52	//
 53	// No scheduled L1Batch
 54	//
 55
 56	// Last L1Batch was a long time ago
 57	stats.Eth.LastBlock.Num = startBlock
 58	stats.Sync.LastBlock = stats.Eth.LastBlock
 59	stats.Sync.LastL1BatchBlock = 0
 60	pipeline.stats = stats
 61	assert.Equal(t, true, pipeline.shouldL1L2Batch(&batchInfo))
 62
 63	stats.Sync.LastL1BatchBlock = startBlock
 64
 65	// We are are one block before the timeout range * 0.5
 66	stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc) - 1
 67	stats.Sync.LastBlock = stats.Eth.LastBlock
 68	pipeline.stats = stats
 69	assert.Equal(t, false, pipeline.shouldL1L2Batch(&batchInfo))
 70
 71	// We are are at timeout range * 0.5
 72	stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc)
 73	stats.Sync.LastBlock = stats.Eth.LastBlock
 74	pipeline.stats = stats
 75	assert.Equal(t, true, pipeline.shouldL1L2Batch(&batchInfo))
 76
 77	//
 78	// Scheduled L1Batch
 79	//
 80	pipeline.lastScheduledL1BatchBlockNum = startBlock
 81	stats.Sync.LastL1BatchBlock = startBlock - 10
 82
 83	// We are are one block before the timeout range * 0.5
 84	stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc) - 1
 85	stats.Sync.LastBlock = stats.Eth.LastBlock
 86	pipeline.stats = stats
 87	assert.Equal(t, false, pipeline.shouldL1L2Batch(&batchInfo))
 88
 89	// We are are at timeout range * 0.5
 90	stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc)
 91	stats.Sync.LastBlock = stats.Eth.LastBlock
 92	pipeline.stats = stats
 93	assert.Equal(t, true, pipeline.shouldL1L2Batch(&batchInfo))
 94}
 95
 96const testTokensLen = 3
 97const testUsersLen = 4
 98
 99func preloadSync(t *testing.T, ethClient *test.Client, sync *synchronizer.Synchronizer,
100	historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) *til.Context {
101	// Create a set with `testTokensLen` tokens and for each token
102	// `testUsersLen` accounts.
103	var set []til.Instruction
104	// set = append(set, til.Instruction{Typ: "Blockchain"})
105	for tokenID := 1; tokenID < testTokensLen; tokenID++ {
106		set = append(set, til.Instruction{
107			Typ:     til.TypeAddToken,
108			TokenID: common.TokenID(tokenID),
109		})
110	}
111	depositAmount, ok := new(big.Int).SetString("10225000000000000000000000000000000", 10)
112	require.True(t, ok)
113	for tokenID := 0; tokenID < testTokensLen; tokenID++ {
114		for user := 0; user < testUsersLen; user++ {
115			set = append(set, til.Instruction{
116				Typ:           common.TxTypeCreateAccountDeposit,
117				TokenID:       common.TokenID(tokenID),
118				DepositAmount: depositAmount,
119				From:          fmt.Sprintf("User%d", user),
120			})
121		}
122	}
123	set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
124	set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
125	set = append(set, til.Instruction{Typ: til.TypeNewBlock})
126
127	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
128	blocks, err := tc.GenerateBlocksFromInstructions(set)
129	require.NoError(t, err)
130	require.NotNil(t, blocks)
131
132	ethAddTokens(blocks, ethClient)
133	err = ethClient.CtlAddBlocks(blocks)
134	require.NoError(t, err)
135
136	ctx := context.Background()
137	for {
138		syncBlock, discards, err := sync.Sync2(ctx, nil)
139		require.NoError(t, err)
140		require.Nil(t, discards)
141		if syncBlock == nil {
142			break
143		}
144	}
145	dbTokens, err := historyDB.GetAllTokens()
146	require.Nil(t, err)
147	require.Equal(t, testTokensLen, len(dbTokens))
148
149	dbAccounts, err := historyDB.GetAllAccounts()
150	require.Nil(t, err)
151	require.Equal(t, testTokensLen*testUsersLen, len(dbAccounts))
152
153	sdbAccounts, err := stateDB.GetAccounts()
154	require.Nil(t, err)
155	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
156
157	return tc
158}
159
160func TestPipelineForgeBatchWithTxs(t *testing.T) {
161	ethClientSetup := test.NewClientSetupExample()
162	ethClientSetup.ChainID = big.NewInt(int64(chainID))
163
164	var timer timer
165	ctx := context.Background()
166	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
167	modules := newTestModules(t)
168	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
169	sync := newTestSynchronizer(t, ethClient, ethClientSetup, modules)
170
171	// preload the synchronier (via the test ethClient) some tokens and
172	// users with positive balances
173	tilCtx := preloadSync(t, ethClient, sync, modules.historyDB, modules.stateDB)
174	syncStats := sync.Stats()
175	batchNum := common.BatchNum(syncStats.Sync.LastBatch)
176	syncSCVars := sync.SCVars()
177
178	pipeline, err := coord.newPipeline(ctx)
179	require.NoError(t, err)
180
181	// Insert some l2txs in the Pool
182	setPool := `
183Type: PoolL2
184
185PoolTransfer(0) User0-User1: 100 (126)
186PoolTransfer(0) User1-User2: 200 (126)
187PoolTransfer(0) User2-User3: 300 (126)
188	`
189	l2txs, err := tilCtx.GeneratePoolL2Txs(setPool)
190	require.NoError(t, err)
191	for _, tx := range l2txs {
192		err := modules.l2DB.AddTxTest(&tx) //nolint:gosec
193		require.NoError(t, err)
194	}
195
196	err = pipeline.reset(batchNum, syncStats, &synchronizer.SCVariables{
197		Rollup:   *syncSCVars.Rollup,
198		Auction:  *syncSCVars.Auction,
199		WDelayer: *syncSCVars.WDelayer,
200	})
201	require.NoError(t, err)
202	// Sanity check
203	sdbAccounts, err := pipeline.txSelector.LocalAccountsDB().GetAccounts()
204	require.Nil(t, err)
205	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
206
207	// Sanity check
208	sdbAccounts, err = pipeline.batchBuilder.LocalStateDB().GetAccounts()
209	require.Nil(t, err)
210	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
211
212	// Sanity check
213	require.Equal(t, modules.stateDB.MT.Root(),
214		pipeline.batchBuilder.LocalStateDB().MT.Root())
215
216	batchNum++
217
218	batchInfo, err := pipeline.forgeBatch(batchNum)
219	require.NoError(t, err)
220	assert.Equal(t, 3, len(batchInfo.L2Txs))
221
222	batchNum++
223	batchInfo, err = pipeline.forgeBatch(batchNum)
224	require.NoError(t, err)
225	assert.Equal(t, 0, len(batchInfo.L2Txs))
226}
227
228func TestEthRollupForgeBatch(t *testing.T) {
229	if os.Getenv("TEST_ROLLUP_FORGE_BATCH") == "" {
230		return
231	}
232	const web3URL = "http://localhost:8545"
233	const password = "test"
234	addr := ethCommon.HexToAddress("0xb4124ceb3451635dacedd11767f004d8a28c6ee7")
235	sk, err := crypto.HexToECDSA(
236		"a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563")
237	require.NoError(t, err)
238	rollupAddr := ethCommon.HexToAddress("0x8EEaea23686c319133a7cC110b840d1591d9AeE0")
239	pathKeystore, err := ioutil.TempDir("", "tmpKeystore")
240	require.NoError(t, err)
241	deleteme = append(deleteme, pathKeystore)
242	ctx := context.Background()
243	batchInfo := &BatchInfo{}
244	proofClient := &prover.MockClient{}
245	chainID := uint16(0)
246
247	ethClient, err := ethclient.Dial(web3URL)
248	require.NoError(t, err)
249	ethCfg := eth.EthereumConfig{
250		CallGasLimit: 300000,
251		GasPriceDiv:  100,
252	}
253	scryptN := ethKeystore.LightScryptN
254	scryptP := ethKeystore.LightScryptP
255	keyStore := ethKeystore.NewKeyStore(pathKeystore,
256		scryptN, scryptP)
257	account, err := keyStore.ImportECDSA(sk, password)
258	require.NoError(t, err)
259	require.Equal(t, account.Address, addr)
260	err = keyStore.Unlock(account, password)
261	require.NoError(t, err)
262
263	client, err := eth.NewClient(ethClient, &account, keyStore, &eth.ClientConfig{
264		Ethereum: ethCfg,
265		Rollup: eth.RollupConfig{
266			Address: rollupAddr,
267		},
268		Auction: eth.AuctionConfig{
269			Address: ethCommon.Address{},
270			TokenHEZ: eth.TokenConfig{
271				Address: ethCommon.Address{},
272				Name:    "HEZ",
273			},
274		},
275		WDelayer: eth.WDelayerConfig{
276			Address: ethCommon.Address{},
277		},
278	})
279	require.NoError(t, err)
280
281	zkInputs := common.NewZKInputs(chainID, 100, 24, 512, 32, big.NewInt(1))
282	zkInputs.Metadata.NewStateRootRaw = &merkletree.Hash{1}
283	zkInputs.Metadata.NewExitRootRaw = &merkletree.Hash{2}
284	batchInfo.ZKInputs = zkInputs
285	err = proofClient.CalculateProof(ctx, batchInfo.ZKInputs)
286	require.NoError(t, err)
287
288	proof, pubInputs, err := proofClient.GetProof(ctx)
289	require.NoError(t, err)
290	batchInfo.Proof = proof
291	batchInfo.PublicInputs = pubInputs
292
293	batchInfo.ForgeBatchArgs = prepareForgeBatchArgs(batchInfo)
294	auth, err := client.NewAuth()
295	require.NoError(t, err)
296	_, err = client.RollupForgeBatch(batchInfo.ForgeBatchArgs, auth)
297	require.NoError(t, err)
298	batchInfo.Proof = proof
299}