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.TestGetAccounts()
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().TestGetAccounts()
204 require.Nil(t, err)
205 require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
206
207 // Sanity check
208 sdbAccounts, err = pipeline.batchBuilder.LocalStateDB().TestGetAccounts()
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, ð.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}