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/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.Compress(),
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			DepositAmount: 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}