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) []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 + 1),
 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}