package test import ( "errors" "fmt" "math/big" "strconv" "time" ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" "github.com/iden3/go-iden3-crypto/babyjub" ) // WARNING: the generators in this file doesn't necessary follow the protocol // they are intended to check that the parsers between struct <==> DB are correct // GenBlocks generates block from, to block numbers. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol. func GenBlocks(from, to int64) []common.Block { var blocks []common.Block for i := from; i < to; i++ { blocks = append(blocks, common.Block{ EthBlockNum: i, //nolint:gomnd Timestamp: time.Now().Add(time.Second * 13).UTC(), Hash: ethCommon.BigToHash(big.NewInt(int64(i))), }) } return blocks } // GenTokens generates tokens. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol. func GenTokens(nTokens int, blocks []common.Block) []common.Token { tokens := []common.Token{} for i := 0; i < nTokens; i++ { token := common.Token{ TokenID: common.TokenID(i), Name: fmt.Sprint(i), Symbol: fmt.Sprint(i), Decimals: uint64(i), EthBlockNum: blocks[i%len(blocks)].EthBlockNum, EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))), } if i%2 == 0 { token.USD = 3 token.USDUpdate = time.Now() } tokens = append(tokens, token) } return tokens } // GenBatches generates batches. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol. func GenBatches(nBatches int, blocks []common.Block) []common.Batch { batches := []common.Batch{} collectedFees := make(map[common.TokenID]*big.Int) for i := 0; i < 64; i++ { collectedFees[common.TokenID(i)] = big.NewInt(int64(i)) } for i := 0; i < nBatches; i++ { batch := common.Batch{ BatchNum: common.BatchNum(i + 1), EthBlockNum: blocks[i%len(blocks)].EthBlockNum, //nolint:gomnd ForgerAddr: ethCommon.BigToAddress(big.NewInt(6886723)), CollectedFees: collectedFees, StateRoot: common.Hash([]byte("duhdqlwiucgwqeiu")), //nolint:gomnd NumAccounts: 30, ExitRoot: common.Hash([]byte("tykertheuhtgenuer3iuw3b")), SlotNum: common.SlotNum(i), } if i%2 == 0 { batch.ForgeL1TxsNum = uint32(i) } batches = append(batches, batch) } return batches } // GenAccounts generates accounts. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol. func GenAccounts(totalAccounts, userAccounts int, tokens []common.Token, userAddr *ethCommon.Address, batches []common.Batch) []common.Account { if totalAccounts < userAccounts { panic("totalAccounts must be greater than userAccounts") } privK := babyjub.NewRandPrivKey() pubK := privK.Public() accs := []common.Account{} for i := 0; i < totalAccounts; i++ { var addr ethCommon.Address if i < userAccounts { addr = *userAddr } else { addr = ethCommon.BigToAddress(big.NewInt(int64(i))) } accs = append(accs, common.Account{ Idx: common.Idx(i), TokenID: tokens[i%len(tokens)].TokenID, EthAddr: addr, BatchNum: batches[i%len(batches)].BatchNum, PublicKey: pubK, }) } return accs } // GenL1Txs generates L1 txs. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol. func GenL1Txs( fromIdx int, totalTxs, nUserTxs int, userAddr *ethCommon.Address, accounts []common.Account, tokens []common.Token, blocks []common.Block, batches []common.Batch, ) ([]common.L1Tx, []common.L1Tx) { if totalTxs < nUserTxs { panic("totalTxs must be greater than userTxs") } userTxs := []common.L1Tx{} othersTxs := []common.L1Tx{} for i := 0; i < totalTxs; i++ { var tx common.L1Tx if batches[i%len(batches)].ForgeL1TxsNum != 0 { tx = common.L1Tx{ TxID: common.TxID(common.Hash([]byte("L1_" + strconv.Itoa(fromIdx+i)))), ToForgeL1TxsNum: batches[i%len(batches)].ForgeL1TxsNum, Position: i, UserOrigin: i%2 == 0, TokenID: tokens[i%len(tokens)].TokenID, Amount: big.NewInt(int64(i + 1)), LoadAmount: big.NewInt(int64(i + 1)), EthBlockNum: blocks[i%len(blocks)].EthBlockNum, Type: randomTxType(i), } if i%4 == 0 { tx.BatchNum = batches[i%len(batches)].BatchNum } } else { continue } if i < nUserTxs { var from, to common.Account var err error if i%2 == 0 { from, err = randomAccount(i, true, userAddr, accounts) if err != nil { panic(err) } to, err = randomAccount(i, false, userAddr, accounts) if err != nil { panic(err) } } else { from, err = randomAccount(i, false, userAddr, accounts) if err != nil { panic(err) } to, err = randomAccount(i, true, userAddr, accounts) if err != nil { panic(err) } } tx.FromIdx = from.Idx tx.FromEthAddr = from.EthAddr tx.FromBJJ = from.PublicKey tx.ToIdx = to.Idx userTxs = append(userTxs, tx) } else { from, err := randomAccount(i, false, userAddr, accounts) if err != nil { panic(err) } to, err := randomAccount(i, false, userAddr, accounts) if err != nil { panic(err) } tx.FromIdx = from.Idx tx.FromEthAddr = from.EthAddr tx.FromBJJ = from.PublicKey tx.ToIdx = to.Idx othersTxs = append(othersTxs, tx) } } return userTxs, othersTxs } // GenL2Txs generates L2 txs. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol. func GenL2Txs( fromIdx int, totalTxs, nUserTxs int, userAddr *ethCommon.Address, accounts []common.Account, tokens []common.Token, blocks []common.Block, batches []common.Batch, ) ([]common.L2Tx, []common.L2Tx) { if totalTxs < nUserTxs { panic("totalTxs must be greater than userTxs") } userTxs := []common.L2Tx{} othersTxs := []common.L2Tx{} for i := 0; i < totalTxs; i++ { tx := common.L2Tx{ TxID: common.TxID(common.Hash([]byte("L2_" + strconv.Itoa(fromIdx+i)))), BatchNum: batches[i%len(batches)].BatchNum, Position: i, //nolint:gomnd Amount: big.NewInt(int64(i + 1)), //nolint:gomnd Fee: common.FeeSelector(i % 256), Nonce: common.Nonce(i + 1), EthBlockNum: blocks[i%len(blocks)].EthBlockNum, Type: randomTxType(i), } if i < nUserTxs { var from, to common.Account var err error if i%2 == 0 { from, err = randomAccount(i, true, userAddr, accounts) if err != nil { panic(err) } to, err = randomAccount(i, false, userAddr, accounts) if err != nil { panic(err) } } else { from, err = randomAccount(i, false, userAddr, accounts) if err != nil { panic(err) } to, err = randomAccount(i, true, userAddr, accounts) if err != nil { panic(err) } } tx.FromIdx = from.Idx tx.ToIdx = to.Idx userTxs = append(userTxs, tx) } else { from, err := randomAccount(i, false, userAddr, accounts) if err != nil { panic(err) } to, err := randomAccount(i, false, userAddr, accounts) if err != nil { panic(err) } tx.FromIdx = from.Idx tx.ToIdx = to.Idx othersTxs = append(othersTxs, tx) } } return userTxs, othersTxs } // GenCoordinators generates coordinators. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol. func GenCoordinators(nCoords int, blocks []common.Block) []common.Coordinator { coords := []common.Coordinator{} for i := 0; i < nCoords; i++ { coords = append(coords, common.Coordinator{ EthBlockNum: blocks[i%len(blocks)].EthBlockNum, Forger: ethCommon.BigToAddress(big.NewInt(int64(i))), Withdraw: ethCommon.BigToAddress(big.NewInt(int64(i))), URL: "https://foo.bar", }) } return coords } // GenBids generates bids. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol. func GenBids(nBids int, blocks []common.Block, coords []common.Coordinator) []common.Bid { bids := []common.Bid{} for i := 0; i < nBids; i++ { bids = append(bids, common.Bid{ SlotNum: common.SlotNum(i), BidValue: big.NewInt(int64(i)), EthBlockNum: blocks[i%len(blocks)].EthBlockNum, ForgerAddr: coords[i%len(blocks)].Forger, }) } return bids } func randomAccount(seed int, userAccount bool, userAddr *ethCommon.Address, accs []common.Account) (common.Account, error) { i := seed % len(accs) firstI := i for { acc := accs[i] if userAccount && *userAddr == acc.EthAddr { return acc, nil } if !userAccount && (userAddr == nil || *userAddr != acc.EthAddr) { return acc, nil } i++ i = i % len(accs) if i == firstI { return acc, errors.New("Didnt found any account matchinng the criteria") } } } func randomTxType(seed int) common.TxType { //nolint:gomnd switch seed % 11 { case 0: return common.TxTypeExit //nolint:gomnd case 1: return common.TxTypeWithdrawn //nolint:gomnd case 2: return common.TxTypeTransfer //nolint:gomnd case 3: return common.TxTypeDeposit //nolint:gomnd case 4: return common.TxTypeCreateAccountDeposit //nolint:gomnd case 5: return common.TxTypeCreateAccountDepositTransfer //nolint:gomnd case 6: return common.TxTypeDepositTransfer //nolint:gomnd case 7: return common.TxTypeForceTransfer //nolint:gomnd case 8: return common.TxTypeForceExit //nolint:gomnd case 9: return common.TxTypeTransferToEthAddr //nolint:gomnd case 10: return common.TxTypeTransferToBJJ default: return common.TxTypeTransfer } }