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