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