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