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