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