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