hermez-node/test/historydb.go
test/historydb.goRaw
1package test
2
3import (
4 "errors"
5 "fmt"
6 "math/big"
7 "time"
8
9 ethCommon "github.com/ethereum/go-ethereum/common"
10 "github.com/hermeznetwork/hermez-node/common"
11 "github.com/iden3/go-iden3-crypto/babyjub"
12 "github.com/iden3/go-merkletree"
13)
14
15// WARNING: the generators in this file doesn't necessary follow the protocol
16// they are intended to check that the parsers between struct <==> DB are correct
17
18// GenBlocks generates block from, to block numbers. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
19func GenBlocks(from, to int64) []common.Block {
20 var blocks []common.Block
21 for i := from; i < to; i++ {
22 blocks = append(blocks, common.Block{
23 EthBlockNum: i,
24 //nolint:gomnd
25 Timestamp: time.Now().Add(time.Second * 13).UTC(),
26 Hash: ethCommon.BigToHash(big.NewInt(int64(i))),
27 })
28 }
29 return blocks
30}
31
32// GenTokens generates tokens. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
33func GenTokens(nTokens int, blocks []common.Block) (tokensToAddInDB []common.Token, ethToken common.Token) {
34 tokensToAddInDB = []common.Token{}
35 for i := 1; i < nTokens; i++ {
36 token := common.Token{
37 TokenID: common.TokenID(i),
38 Name: "NAME" + fmt.Sprint(i),
39 Symbol: fmt.Sprint(i),
40 Decimals: uint64(i + 1),
41 EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
42 EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
43 }
44 tokensToAddInDB = append(tokensToAddInDB, token)
45 }
46 return tokensToAddInDB, common.Token{
47 TokenID: 0,
48 Name: "Ether",
49 Symbol: "ETH",
50 Decimals: 18, //nolint:gomnd
51 EthBlockNum: 0,
52 EthAddr: ethCommon.BigToAddress(big.NewInt(0)),
53 }
54}
55
56// GenBatches generates batches. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
57func GenBatches(nBatches int, blocks []common.Block) []common.Batch {
58 batches := []common.Batch{}
59 collectedFees := make(map[common.TokenID]*big.Int)
60 for i := 0; i < 64; i++ {
61 collectedFees[common.TokenID(i)] = big.NewInt(int64(i))
62 }
63 for i := 0; i < nBatches; i++ {
64 batch := common.Batch{
65 BatchNum: common.BatchNum(i + 1),
66 EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
67 //nolint:gomnd
68 ForgerAddr: ethCommon.BigToAddress(big.NewInt(6886723)),
69 CollectedFees: collectedFees,
70 StateRoot: big.NewInt(int64(i+1) * 5), //nolint:gomnd
71 //nolint:gomnd
72 NumAccounts: 30,
73 ExitRoot: big.NewInt(int64(i+1) * 16), //nolint:gomnd
74 SlotNum: int64(i),
75 }
76 if i%2 == 0 {
77 toForge := new(int64)
78 *toForge = int64(i + 1)
79 batch.ForgeL1TxsNum = toForge
80 }
81 batches = append(batches, batch)
82 }
83 return batches
84}
85
86// GenAccounts generates accounts. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
87func GenAccounts(totalAccounts, userAccounts int, tokens []common.Token, userAddr *ethCommon.Address, userBjj *babyjub.PublicKey, batches []common.Batch) []common.Account {
88 if totalAccounts < userAccounts {
89 panic("totalAccounts must be greater than userAccounts")
90 }
91 accs := []common.Account{}
92 for i := 256; i < 256+totalAccounts; i++ {
93 var addr ethCommon.Address
94 var pubK *babyjub.PublicKey
95 if i < 256+userAccounts {
96 addr = *userAddr
97 pubK = userBjj
98 } else {
99 addr = ethCommon.BigToAddress(big.NewInt(int64(i)))
100 privK := babyjub.NewRandPrivKey()
101 pubK = privK.Public()
102 }
103 accs = append(accs, common.Account{
104 Idx: common.Idx(i),
105 TokenID: tokens[i%len(tokens)].TokenID,
106 EthAddr: addr,
107 BatchNum: batches[i%len(batches)].BatchNum,
108 PublicKey: pubK,
109 Balance: big.NewInt(int64(i * 10000000)), //nolint:gomnd
110 })
111 }
112 return accs
113}
114
115// GenL1Txs generates L1 txs. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
116func GenL1Txs(
117 fromIdx int,
118 totalTxs, nUserTxs int,
119 userAddr *ethCommon.Address,
120 accounts []common.Account,
121 tokens []common.Token,
122 blocks []common.Block,
123 batches []common.Batch,
124) ([]common.L1Tx, []common.L1Tx) {
125 if totalTxs < nUserTxs {
126 panic("totalTxs must be greater than userTxs")
127 }
128 userTxs := []common.L1Tx{}
129 othersTxs := []common.L1Tx{}
130 _, nextTxsNum := GetNextToForgeNumAndBatch(batches)
131 for i := fromIdx; i < fromIdx+totalTxs; i++ {
132 token := tokens[i%len(tokens)]
133 amount := big.NewInt(int64(i + 1))
134 tx := common.L1Tx{
135 Position: i - fromIdx,
136 UserOrigin: i%2 == 0,
137 TokenID: token.TokenID,
138 Amount: amount,
139 LoadAmount: amount,
140 EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
141 }
142 if tx.UserOrigin {
143 n := nextTxsNum
144 tx.ToForgeL1TxsNum = &n
145 } else {
146 tx.BatchNum = &batches[i%len(batches)].BatchNum
147 }
148 nTx, err := common.NewL1Tx(&tx)
149 if err != nil {
150 panic(err)
151 }
152 tx = *nTx
153 if !tx.UserOrigin {
154 tx.BatchNum = &batches[i%len(batches)].BatchNum
155 } else if batches[i%len(batches)].ForgeL1TxsNum != nil {
156 // Add already forged txs
157 tx.BatchNum = &batches[i%len(batches)].BatchNum
158 setFromToAndAppend(fromIdx, tx, i, nUserTxs, userAddr, accounts, &userTxs, &othersTxs)
159 } else {
160 // Add unforged txs
161 n := nextTxsNum
162 tx.ToForgeL1TxsNum = &n
163 tx.UserOrigin = true
164 setFromToAndAppend(fromIdx, tx, i, nUserTxs, userAddr, accounts, &userTxs, &othersTxs)
165 }
166 }
167 return userTxs, othersTxs
168}
169
170// GetNextToForgeNumAndBatch returns the next BatchNum and ForgeL1TxsNum to be added
171func GetNextToForgeNumAndBatch(batches []common.Batch) (common.BatchNum, int64) {
172 batchNum := batches[len(batches)-1].BatchNum + 1
173 var toForgeL1TxsNum int64
174 found := false
175 for i := len(batches) - 1; i >= 0; i-- {
176 if batches[i].ForgeL1TxsNum != nil {
177 toForgeL1TxsNum = *batches[i].ForgeL1TxsNum + 1
178 found = true
179 break
180 }
181 }
182 if !found {
183 panic("toForgeL1TxsNum not found")
184 }
185 return batchNum, toForgeL1TxsNum
186}
187
188func setFromToAndAppend(
189 fromIdx int,
190 tx common.L1Tx,
191 i, nUserTxs int,
192 userAddr *ethCommon.Address,
193 accounts []common.Account,
194 userTxs *[]common.L1Tx,
195 othersTxs *[]common.L1Tx,
196) {
197 if i < fromIdx+nUserTxs {
198 var from, to *common.Account
199 var err error
200 if i%2 == 0 {
201 from, err = randomAccount(i, true, userAddr, accounts)
202 if err != nil {
203 panic(err)
204 }
205 to, err = randomAccount(i, false, userAddr, accounts)
206 if err != nil {
207 panic(err)
208 }
209 } else {
210 from, err = randomAccount(i, false, userAddr, accounts)
211 if err != nil {
212 panic(err)
213 }
214 to, err = randomAccount(i, true, userAddr, accounts)
215 if err != nil {
216 panic(err)
217 }
218 }
219 tx.FromIdx = from.Idx
220 tx.FromEthAddr = from.EthAddr
221 tx.FromBJJ = from.PublicKey
222 tx.ToIdx = to.Idx
223 *userTxs = append(*userTxs, tx)
224 } else {
225 from, err := randomAccount(i, false, userAddr, accounts)
226 if err != nil {
227 panic(err)
228 }
229 to, err := randomAccount(i, false, userAddr, accounts)
230 if err != nil {
231 panic(err)
232 }
233 tx.FromIdx = from.Idx
234 tx.FromEthAddr = from.EthAddr
235 tx.FromBJJ = from.PublicKey
236 tx.ToIdx = to.Idx
237 *othersTxs = append(*othersTxs, tx)
238 }
239}
240
241// GenL2Txs generates L2 txs. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
242func GenL2Txs(
243 fromIdx int,
244 totalTxs, nUserTxs int,
245 userAddr *ethCommon.Address,
246 accounts []common.Account,
247 tokens []common.Token,
248 blocks []common.Block,
249 batches []common.Batch,
250) ([]common.L2Tx, []common.L2Tx) {
251 if totalTxs < nUserTxs {
252 panic("totalTxs must be greater than userTxs")
253 }
254 userTxs := []common.L2Tx{}
255 othersTxs := []common.L2Tx{}
256 for i := fromIdx; i < fromIdx+totalTxs; i++ {
257 amount := big.NewInt(int64(i + 1))
258 fee := common.FeeSelector(i % 256) //nolint:gomnd
259 tx := common.L2Tx{
260 TxID: common.TxID([12]byte{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, byte(i)}), // only for testing purposes
261 BatchNum: batches[i%len(batches)].BatchNum,
262 Position: i - fromIdx,
263 Amount: amount,
264 Fee: fee,
265 Nonce: common.Nonce(i + 1),
266 EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
267 Type: randomTxType(i),
268 }
269 if i < nUserTxs {
270 var from, to *common.Account
271 var err error
272 if i%2 == 0 {
273 from, err = randomAccount(i, true, userAddr, accounts)
274 if err != nil {
275 panic(err)
276 }
277 to, err = randomAccount(i, false, userAddr, accounts)
278 if err != nil {
279 panic(err)
280 }
281 } else {
282 from, err = randomAccount(i, false, userAddr, accounts)
283 if err != nil {
284 panic(err)
285 }
286 to, err = randomAccount(i, true, userAddr, accounts)
287 if err != nil {
288 panic(err)
289 }
290 }
291 tx.FromIdx = from.Idx
292 tx.ToIdx = to.Idx
293 } else {
294 from, err := randomAccount(i, false, userAddr, accounts)
295 if err != nil {
296 panic(err)
297 }
298 to, err := randomAccount(i, false, userAddr, accounts)
299 if err != nil {
300 panic(err)
301 }
302 tx.FromIdx = from.Idx
303 tx.ToIdx = to.Idx
304 }
305
306 if i < nUserTxs {
307 userTxs = append(userTxs, tx)
308 } else {
309 othersTxs = append(othersTxs, tx)
310 }
311 }
312 return userTxs, othersTxs
313}
314
315// GenCoordinators generates coordinators. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
316func GenCoordinators(nCoords int, blocks []common.Block) []common.Coordinator {
317 coords := []common.Coordinator{}
318 for i := 0; i < nCoords; i++ {
319 coords = append(coords, common.Coordinator{
320 EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
321 Forger: ethCommon.BigToAddress(big.NewInt(int64(i))),
322 Bidder: ethCommon.BigToAddress(big.NewInt(int64(i))),
323 URL: "https://foo.bar",
324 })
325 }
326 return coords
327}
328
329// GenBids generates bids. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
330func GenBids(nBids int, blocks []common.Block, coords []common.Coordinator) []common.Bid {
331 bids := []common.Bid{}
332 for i := 0; i < nBids; i++ {
333 bids = append(bids, common.Bid{
334 SlotNum: int64(i),
335 BidValue: big.NewInt(int64(i)),
336 EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
337 Bidder: coords[i%len(blocks)].Bidder,
338 })
339 }
340 return bids
341}
342
343// GenExitTree generates an exitTree (as an array of Exits)
344//nolint:gomnd
345func GenExitTree(n int, batches []common.Batch, accounts []common.Account) []common.ExitInfo {
346 exitTree := make([]common.ExitInfo, n)
347 for i := 0; i < n; i++ {
348 exitTree[i] = common.ExitInfo{
349 BatchNum: batches[i%len(batches)].BatchNum,
350 InstantWithdrawn: nil,
351 DelayedWithdrawRequest: nil,
352 DelayedWithdrawn: nil,
353 AccountIdx: accounts[i%len(accounts)].Idx,
354 MerkleProof: &merkletree.CircomVerifierProof{
355 Root: &merkletree.Hash{byte(i), byte(i + 1)},
356 Siblings: []*big.Int{
357 big.NewInt(int64(i) * 10),
358 big.NewInt(int64(i)*100 + 1),
359 big.NewInt(int64(i)*1000 + 2)},
360 OldKey: &merkletree.Hash{byte(i * 1), byte(i*1 + 1)},
361 OldValue: &merkletree.Hash{byte(i * 2), byte(i*2 + 1)},
362 IsOld0: i%2 == 0,
363 Key: &merkletree.Hash{byte(i * 3), byte(i*3 + 1)},
364 Value: &merkletree.Hash{byte(i * 4), byte(i*4 + 1)},
365 Fnc: i % 2,
366 },
367 Balance: big.NewInt(int64(i) * 1000),
368 }
369 if i%2 == 0 {
370 instant := new(int64)
371 *instant = int64(batches[(i+1)%len(batches)].BatchNum)
372 exitTree[i].InstantWithdrawn = instant
373 } else if i%3 == 0 {
374 delayedReq := new(int64)
375 *delayedReq = int64(batches[(i+1)%len(batches)].BatchNum)
376 exitTree[i].DelayedWithdrawRequest = delayedReq
377 if i%9 == 0 {
378 delayed := new(int64)
379 *delayed = int64(batches[(i+2)%len(batches)].BatchNum)
380 exitTree[i].DelayedWithdrawn = delayed
381 }
382 }
383 }
384 return exitTree
385}
386
387func randomAccount(seed int, userAccount bool, userAddr *ethCommon.Address, accs []common.Account) (*common.Account, error) {
388 i := seed % len(accs)
389 firstI := i
390 for {
391 acc := accs[i]
392 if userAccount && *userAddr == acc.EthAddr {
393 return &acc, nil
394 }
395 if !userAccount && (userAddr == nil || *userAddr != acc.EthAddr) {
396 return &acc, nil
397 }
398 i++
399 i = i % len(accs)
400 if i == firstI {
401 return &acc, errors.New("Didnt found any account matchinng the criteria")
402 }
403 }
404}
405
406func randomTxType(seed int) common.TxType {
407 //nolint:gomnd
408 switch seed % 11 {
409 case 0:
410 return common.TxTypeExit
411 //nolint:gomnd
412 case 2:
413 return common.TxTypeTransfer
414 //nolint:gomnd
415 case 3:
416 return common.TxTypeDeposit
417 //nolint:gomnd
418 case 4:
419 return common.TxTypeCreateAccountDeposit
420 //nolint:gomnd
421 case 5:
422 return common.TxTypeCreateAccountDepositTransfer
423 //nolint:gomnd
424 case 6:
425 return common.TxTypeDepositTransfer
426 //nolint:gomnd
427 case 7:
428 return common.TxTypeForceTransfer
429 //nolint:gomnd
430 case 8:
431 return common.TxTypeForceExit
432 //nolint:gomnd
433 case 9:
434 return common.TxTypeTransferToEthAddr
435 //nolint:gomnd
436 case 10:
437 return common.TxTypeTransferToBJJ
438 default:
439 return common.TxTypeTransfer
440 }
441}