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