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