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