run

package
v3.8.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 10, 2022 License: LGPL-3.0 Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
const (
	None int = iota
	TransferTx
	ContractTransferTx
	GasTx
	RAMTx
	AccountTx
	ExchangeTransferTx
)

The type of transaction.

Variables

View Source
var AccountCaseAction = func(c *cli.Context) error {
	anum := c.GlobalInt("anum")
	output := c.GlobalString("account")
	keysfile := c.GlobalString("keys")
	configfile := c.GlobalString("config")

	it, err := itest.Load(keysfile, configfile)
	if err != nil {
		return err
	}

	accounts, err := it.CreateAccountN(anum, false, true)
	if err != nil {
		return err
	}

	if err := itest.DumpAccounts(accounts, output); err != nil {
		return err
	}

	return nil
}

AccountCaseAction is the action of account test case

View Source
var AccountCaseCommand = cli.Command{
	Name:      "account_case",
	ShortName: "a_case",
	Usage:     "run account test case",
	Action:    AccountCaseAction,
}

AccountCaseCommand is the command of account test case

View Source
var AccountRoundAction = func(c *cli.Context) error {
	itest.Interval = 2 * time.Millisecond
	itest.InitAmount = "1000"
	itest.InitPledge = "1000"
	itest.InitRAM = "3000"
	logger := ilog.New()
	fileWriter := ilog.NewFileWriter(c.GlobalString("log"))
	fileWriter.SetLevel(ilog.LevelInfo)
	logger.AddWriter(fileWriter)
	ilog.InitLogger(logger)
	keysfile := c.GlobalString("keys")
	configfile := c.GlobalString("config")

	it, err := itest.Load(keysfile, configfile)
	if err != nil {
		return err
	}
	start := c.Int("start")
	round := c.Int("round")

	for i := start; i < start+round; i++ {
		accounts, err := it.CreateAccountRoundN(10000, false, true, i)
		if err != nil {
			return err
		}

		outputFile := "output_acc" + strconv.FormatInt(int64(i), 10) + ".json"
		ilog.Infof("before dump account %v\n", outputFile)
		if err := itest.DumpAccounts(accounts, outputFile); err != nil {
			return err
		}
	}

	return nil
}

AccountRoundAction is the action of account test round

View Source
var AccountRoundCommand = cli.Command{
	Name:      "account_round",
	ShortName: "a_round",
	Usage:     "run account test round",
	Flags:     AccountRoundFlags,
	Action:    AccountRoundAction,
}

AccountRoundCommand is the command of account test round

View Source
var AccountRoundFlags = []cli.Flag{
	cli.IntFlag{
		Name:  "start",
		Value: 1,
		Usage: "start round",
	},
	cli.IntFlag{
		Name:  "round",
		Value: 100,
		Usage: "round number",
	},
}

AccountRoundFlags is the list of flags for account round.

View Source
var BenchmarkAccountAction = func(c *cli.Context) error {
	rand.Seed(time.Now().UTC().UnixNano())
	itest.Interval = 1000 * time.Millisecond
	itest.InitAmount = "1000"
	itest.InitPledge = "1000"
	itest.InitRAM = "3000"

	it, err := itest.Load(c.GlobalString("keys"), c.GlobalString("config"))
	if err != nil {
		return err
	}
	accountFile := c.GlobalString("account")
	accounts, err := itest.LoadAccounts(accountFile)
	if err != nil {
		ilog.Warnf("load accounts from %v failed, creating...%v", accountFile, err)
		if err := AccountCaseAction(c); err != nil {
			return err
		}
		if accounts, err = itest.LoadAccounts(accountFile); err != nil {
			return err
		}
	}
	ilog.Infof("accounts num %v", len(accounts))
	tps := c.Int("tps")
	ilog.Infof("target tps %v", tps)

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	startTime := time.Now()
	ticker := time.NewTicker(time.Second)
	counter := 0
	total := 0
	slotTotal := 0
	slotStartTime := startTime

	checkReceiptConcurrent := 64

	hashCh := make(chan *hashItem, 4*tps*int(itest.Timeout.Seconds()))
	for c := 0; c < checkReceiptConcurrent; c++ {
		go func(hashCh chan *hashItem) {
			counter := 0
			failedCounter := 0
			for item := range hashCh {
				client := it.GetClients()[rand.Intn(len(it.GetClients()))]
				_, err := client.CheckTransactionWithTimeout(item.hash, item.expire)
				counter++
				if err != nil {
					ilog.Errorf("check transaction failed, %v", err)
					failedCounter++
				}

				if counter%1000 == 0 {
					ilog.Warnf("check %v transaction, %v successful, %v failed.", counter, counter-failedCounter, failedCounter)
				}
				if len(hashCh) > 3*tps*int(itest.Timeout.Seconds()) {
					ilog.Infof("hash ch size too large %v", len(hashCh))
				}
			}
		}(hashCh)
	}
	check := c.Bool("check")

	for {
		trxs, err := generateAccountTxs(it, accounts, tps)
		if err != nil {
			ilog.Errorf("generateAccountTxs error %v", err)
			continue
		}
		hashList, errList := it.SendTransactionN(trxs, false)
		ilog.Warnf("Send %v trxs, got %v hash, %v err", len(trxs), len(hashList), len(errList))

		if check {
			expire := time.Now().Add(itest.Timeout)
			for _, hash := range hashList {
				select {
				case hashCh <- &hashItem{hash: hash, expire: expire}:
				case <-time.After(1 * time.Millisecond):
				}
			}
		}

		select {
		case <-sig:
			return fmt.Errorf("signal %v", sig)
		case <-ticker.C:
		}

		counter++
		slotTotal += len(trxs)
		if counter == 10 {
			total += slotTotal
			currentTps := float64(slotTotal) / time.Since(slotStartTime).Seconds()
			averageTps := float64(total) / time.Since(startTime).Seconds()
			ilog.Warnf("Current tps %v, Average tps %v, Total tx %v", currentTps, averageTps, total)
			counter = 0
			slotTotal = 0
			slotStartTime = time.Now()
		}
	}
}

BenchmarkAccountAction is the action of benchmark.

View Source
var BenchmarkAccountCommand = cli.Command{
	Name:      "benchmarkAccount",
	ShortName: "benchA",
	Usage:     "Run account benchmark by given tps",
	Flags:     BenchmarkAccountFlags,
	Action:    BenchmarkAccountAction,
}

BenchmarkAccountCommand is the subcommand for benchmark.

View Source
var BenchmarkAccountFlags = []cli.Flag{
	cli.IntFlag{
		Name:  "tps",
		Value: 20,
		Usage: "The expected ratio of transactions per second",
	},
	cli.BoolFlag{
		Name:  "check",
		Usage: "if check receipt",
	},
}

BenchmarkAccountFlags is the list of flags for benchmark.

View Source
var BenchmarkAction = func(c *cli.Context) error {
	it, err := itest.Load(c.GlobalString("keys"), c.GlobalString("config"))
	if err != nil {
		return err
	}

	txType := None
	cid := ""
	switch c.String("type") {
	case "t", "transfer":
		txType = TransferTx
	case "c", "contract":
		txType = ContractTransferTx
		contract, err := itest.LoadContract(c.GlobalString("code"), c.GlobalString("abi"))
		if err != nil {
			return err
		}
		cid, err = it.SetContract(contract)
		if err != nil {
			return err
		}
	case "g", "gas":
		txType = GasTx
	case "r", "ram":
		txType = RAMTx
	case "a", "account":
		txType = AccountTx
		err := it.Pledge(it.GetDefaultAccount(), "10000000", true)
		if err != nil {
			return err
		}
		itest.InitAmount = "10"
		itest.InitPledge = "20"
		itest.InitRAM = "1000"
	case "e", "exchange":
		txType = ExchangeTransferTx
	default:
		return fmt.Errorf("wrong transaction type: %v", txType)
	}

	accountFile := c.GlobalString("account")
	accounts, err := itest.LoadAccounts(accountFile)
	if err != nil {
		if err := AccountCaseAction(c); err != nil {
			return err
		}
		if accounts, err = itest.LoadAccounts(accountFile); err != nil {
			return err
		}
	}

	tps := c.Int("tps")
	memoSize := c.Int("memo")

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	startTime := time.Now()
	ticker := time.NewTicker(time.Second)
	counter := 0
	total := 0
	slotTotal := 0
	slotStartTime := startTime
	for {
		num := 0
		if txType == TransferTx {
			num, err = it.TransferN(tps, accounts, memoSize, false)
		} else if txType == ContractTransferTx {
			num, err = it.ContractTransferN(cid, tps, accounts, memoSize, false)
		} else if txType == GasTx {
			num, err = it.PledgeGasN("rand", tps, accounts, false)
		} else if txType == RAMTx {
			num, err = it.BuyRAMN("rand", tps, accounts, false)
		} else if txType == AccountTx {
			var accs []*itest.Account
			accs, err = it.CreateAccountN(tps, true, false)
			num = len(accs)
		} else if txType == ExchangeTransferTx {
			num, err = it.ExchangeTransferN(tps, accounts, memoSize, false)
		} else {
			panic("invalid tx type, check --type flag")
		}
		if err != nil {
			ilog.Infoln(err)
		}
		select {
		case <-sig:
			return itest.DumpAccounts(accounts, accountFile)
		case <-ticker.C:
		}

		counter++
		slotTotal += num
		if counter == 10 {
			total += slotTotal
			currentTps := float64(slotTotal) / time.Since(slotStartTime).Seconds()
			averageTps := float64(total) / time.Since(startTime).Seconds()
			ilog.Warnf("Current tps %v, Average tps %v, Total tx %v", currentTps, averageTps, total)
			counter = 0
			slotTotal = 0
			slotStartTime = time.Now()
		}
	}
}

BenchmarkAction is the action of benchmark.

View Source
var BenchmarkCommand = cli.Command{
	Name:      "benchmark",
	ShortName: "bench",
	Usage:     "Run benchmark by given tps",
	Flags:     BenchmarkFlags,
	Action:    BenchmarkAction,
}

BenchmarkCommand is the subcommand for benchmark.

View Source
var BenchmarkFlags = []cli.Flag{
	cli.IntFlag{
		Name:  "tps",
		Value: 100,
		Usage: "The expected ratio of transactions per second",
	},
	cli.StringFlag{
		Name:  "type",
		Value: "t",
		Usage: "The type of transaction, should be one of ['t'/'transfer', 'c'/'contract']",
	},
	cli.IntFlag{
		Name:  "memo, m",
		Value: 0,
		Usage: "The size of a random memo message that would be contained in the transaction",
	},
}

BenchmarkFlags is the list of flags for benchmark.

View Source
var BenchmarkRPCAction = func(c *cli.Context) error {
	it, err := itest.Load(c.GlobalString("keys"), c.GlobalString("config"))
	if err != nil {
		return err
	}

	interval := c.Float64("interval")
	go loopCreateAccount(it, interval)
	go loopGetAccount(it, interval)
	go loopGetChainInfo(it, interval)
	go loopGetContract(it, interval)
	go loopGetGasRatio(it, interval)
	go loopGetNodeInfo(it, interval)
	go loopGetRAMInfo(it, interval)
	go loopGetStorage(it, interval)

	lastCount := 0
	lastTime := time.Now()
	for {
		time.Sleep(time.Second)
		currentTps := float64(rpcCount-lastCount) / time.Since(lastTime).Seconds()
		ilog.Infof("Current tps %v", currentTps)
		lastCount = rpcCount
		lastTime = time.Now()
	}
}

BenchmarkRPCAction is the action of benchmark.

View Source
var BenchmarkRPCCommand = cli.Command{
	Name:      "benchmark_rpc",
	ShortName: "bench_rpc",
	Usage:     "Run benchmark rpc by given tps",
	Flags:     BenchmarkRPCFlags,
	Action:    BenchmarkRPCAction,
}

BenchmarkRPCCommand is the subcommand for benchmark.

View Source
var BenchmarkRPCFlags = []cli.Flag{
	cli.Float64Flag{
		Name:  "interval",
		Value: 0.2,
		Usage: "The interval (in second) between every call",
	},
}

BenchmarkRPCFlags is the list of flags for benchmark.

View Source
var BenchmarkSystemAction = func(c *cli.Context) error {
	itest.Interval = 1000 * time.Millisecond
	itest.InitAmount = "1000"
	itest.InitPledge = "1000"
	itest.InitRAM = "3000"
	logger := ilog.New()
	fileWriter := ilog.NewFileWriter(c.GlobalString("log"))
	fileWriter.SetLevel(ilog.LevelInfo)
	logger.AddWriter(fileWriter)
	ilog.InitLogger(logger)

	it, err := itest.Load(c.GlobalString("keys"), c.GlobalString("config"))
	if err != nil {
		return err
	}
	accountFile := c.GlobalString("account")
	accounts, err := itest.LoadAccounts(accountFile)
	if err != nil {
		if err := AccountCaseAction(c); err != nil {
			return err
		}
		if accounts, err = itest.LoadAccounts(accountFile); err != nil {
			return err
		}
	}
	accountMap := make(map[string]*itest.Account)
	for _, acc := range accounts {
		accountMap[acc.ID] = acc
	}
	tps := c.Int("tps")

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	startTime := time.Now()
	ticker := time.NewTicker(time.Second)
	counter := 0
	total := 0
	slotTotal := 0
	slotStartTime := startTime

	code := `
				class Test {
					init() {}
					hello() { return "world"; }
					can_update(data) { return blockchain.requireAuth(blockchain.contractOwner(), "active"); }
				};
				module.exports = Test;
				`
	ABI := `
				{
					"lang": "javascript",
					"version": "1.0.0",
					"abi": [
						{"name": "hello", "args": [], "amountLimit": [] },
						{"name": "can_update", "args": ["string"], "amountLimit": [] }
					]
				}
				`
	contract, err := itest.NewContract(code, ABI)
	if err != nil {
		return err
	}

	checkReceiptConcurrent := 64
	var contractMutex sync.Mutex
	contractList := make([]string, 0)
	contractMap := make(map[string]string)
	delayTxList := make([]string, 0)

	hashCh := make(chan *hashItem, 4*tps*int(itest.Timeout.Seconds()))
	for c := 0; c < checkReceiptConcurrent; c++ {
		go func(hashCh chan *hashItem) {
			counter := 0
			failedCounter := 0
			for item := range hashCh {
				client := it.GetClients()[rand.Intn(len(it.GetClients()))]
				_, err := client.CheckTransactionWithTimeout(item.hash, item.expire)

				counter++
				if err != nil {
					ilog.Errorf("check transaction failed, %v", err)
					failedCounter++
				}
				if counter%1000 == 0 {
					ilog.Warnf("check %v transaction, %v successful, %v failed.", counter, counter-failedCounter, failedCounter)
				}
				if len(hashCh) > 3*tps*int(itest.Timeout.Seconds()) {
					ilog.Infof("hash ch size too large %v", len(hashCh))
				}
			}
		}(hashCh)
	}

	check := c.Bool("check")
	contractName := "system.iost"
	for {
		trxs := make([]*itest.Transaction, 0)
		errList := []error{}
		contractMutex.Lock()
		for num := 0; num < tps; num++ {

			tIndex := rand.Intn(5)
			var abiName string
			switch {
			case tIndex <= 0 || len(contractList) == 0:
				abiName = setCode
				from := accounts[rand.Intn(len(accounts))]

				act0 := tx.NewAction("ram.iost", "buy", fmt.Sprintf(`["%v", "%v", %v]`, "admin", from.ID, 3000))
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 100))
				tx0 := itest.NewTransaction([]*tx.Action{act0, act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v"]`, contract))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					hash, err := it.SendTransaction(trx, true)
					if err != nil {
						errList = append(errList, err)
					} else {
						contractID := fmt.Sprintf("Contract%v", hash)
						contractList = append(contractList, contractID)
						contractMap[contractID] = from.ID
					}
				}
			case tIndex <= 1:
				abiName = updateCode
				contractID := contractList[rand.Intn(len(contractList))]
				owner := accountMap[contractMap[contractID]]
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", owner.ID, 100))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				contract.ID = contractID
				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", ""]`, contract))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = owner.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 2:
				abiName = cancelDelaytx
				if len(delayTxList) == 0 {
					from := accounts[rand.Intn(len(accounts))]
					act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
					tx0 := itest.NewTransaction([]*tx.Action{act1})
					tx0.Delay = 90 * 1e9
					trx, err := it.GetDefaultAccount().Sign(tx0)
					if err != nil {
						errList = append(errList, err)
					} else {
						hash, err := it.SendTransaction(trx, false)
						if err != nil {
							errList = append(errList, err)
						} else {
							delayTxList = append(delayTxList, hash)
						}
					}
				} else {
					ilog.Infof("cancel delay tx")
					act1 := tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v"]`, delayTxList[0]))
					delayTxList = delayTxList[1:]
					tx1 := itest.NewTransaction([]*tx.Action{act1})
					trx, err := it.GetDefaultAccount().Sign(tx1)
					if err != nil {
						errList = append(errList, err)
					} else {
						trxs = append(trxs, trx)
					}
				}
			case tIndex <= 3:
				abiName = receipt
				from := accounts[rand.Intn(len(accounts))]
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v"]`, from.ID))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 4:
				abiName = requireAuth
				from := accounts[rand.Intn(len(accounts))]
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "owner"]`, from.ID))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			}
		}
		contractMutex.Unlock()
		hashList, tmpList := it.SendTransactionN(trxs, false)
		errList = append(errList, tmpList...)
		ilog.Warnf("Send %v trxs, got %v hash, %v err", len(trxs), len(hashList), len(errList))

		if check {
			expire := time.Now().Add(itest.Timeout)
			for _, hash := range hashList {
				select {
				case hashCh <- &hashItem{hash: hash, expire: expire}:
				case <-time.After(1 * time.Millisecond):
				}
			}
		}

		select {
		case <-sig:
			return fmt.Errorf("signal %v", sig)
		case <-ticker.C:
		}

		counter++
		slotTotal += len(trxs)
		if counter == 10 {
			total += slotTotal
			currentTps := float64(slotTotal) / time.Since(slotStartTime).Seconds()
			averageTps := float64(total) / time.Since(startTime).Seconds()
			ilog.Warnf("Current tps %v, Average tps %v, Total tx %v, contractNum %v, delaytxNum %v", currentTps, averageTps, total, len(contractList), len(delayTxList))
			counter = 0
			slotTotal = 0
			slotStartTime = time.Now()
		}
	}
}

BenchmarkSystemAction is the action of benchmark.

View Source
var BenchmarkSystemCommand = cli.Command{
	Name:      "benchmarkSystem",
	ShortName: "benchS",
	Usage:     "Run system benchmark by given tps",
	Flags:     BenchmarkSystemFlags,
	Action:    BenchmarkSystemAction,
}

BenchmarkSystemCommand is the subcommand for benchmark system.iost.

View Source
var BenchmarkSystemFlags = []cli.Flag{
	cli.IntFlag{
		Name:  "tps",
		Value: 50,
		Usage: "The expected ratio of transactions per second",
	},
	cli.BoolFlag{
		Name:  "check",
		Usage: "if check receipt",
	},
}

BenchmarkSystemFlags is the list of flags for benchmark.

View Source
var BenchmarkToken721Action = func(c *cli.Context) error {
	itest.Interval = 1000 * time.Millisecond
	itest.InitAmount = "1000"
	itest.InitPledge = "1000"
	itest.InitRAM = "3000"
	logger := ilog.New()
	fileWriter := ilog.NewFileWriter(c.GlobalString("log"))
	fileWriter.SetLevel(ilog.LevelInfo)
	logger.AddWriter(fileWriter)
	ilog.InitLogger(logger)

	it, err := itest.Load(c.GlobalString("keys"), c.GlobalString("config"))
	if err != nil {
		return err
	}
	accountFile := c.GlobalString("account")
	accounts, err := itest.LoadAccounts(accountFile)
	if err != nil {
		if err := AccountCaseAction(c); err != nil {
			return err
		}
		if accounts, err = itest.LoadAccounts(accountFile); err != nil {
			return err
		}
	}
	accountMap := make(map[string]*itest.Account)
	for _, acc := range accounts {
		accountMap[acc.ID] = acc
	}
	tps := c.Int("tps")

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	startTime := time.Now()
	ticker := time.NewTicker(time.Second)
	counter := 0
	total := 0
	slotTotal := 0
	slotStartTime := startTime
	issueNumber := 5
	checkReceiptConcurrent := 64

	tokenList := []string{}
	tokenMap := make(map[string]*token721Info)
	tokenPrefix := "t" + strconv.FormatInt(time.Now().UnixNano(), 10)[14:]
	tokenOffset := 0
	var tokenMutex sync.Mutex

	hashCh := make(chan *hashItem, 4*tps*int(itest.Timeout.Seconds()))

	for c := 0; c < checkReceiptConcurrent; c++ {
		go func(hashCh chan *hashItem) {
			counter := 0
			failedCounter := 0
			for item := range hashCh {
				client := it.GetClients()[rand.Intn(len(it.GetClients()))]
				r, err := client.CheckTransactionWithTimeout(item.hash, item.expire)
				ilog.Debugf("receipt: %v", r)
				counter++
				if err != nil {
					ilog.Errorf("check transaction failed, %v", err)
					failedCounter++
				} else {
					for i := 0; i < len(r.Receipts); i++ {
						if r.Receipts[i].FuncName == "token721.iost/issue" {
							args := make([]string, 3)
							err := json.Unmarshal([]byte(r.Receipts[i].Content), &args)
							if err != nil {
								continue
							}
							ilog.Debugf("got receipt %v %v", r.Receipts[i], args)
							tokenMutex.Lock()
							tokenSym := args[0]
							acc := args[1]
							for j := 0; j < len(r.Returns); j++ {
								ret := r.Returns[j]
								ret = ret[2:(len(ret) - 2)]
								if _, ok := tokenMap[tokenSym].balance[acc]; !ok {
									tokenMap[tokenSym].balance[acc] = make([]string, 0)
									tokenMap[tokenSym].acclist = append(tokenMap[tokenSym].acclist, acc)
								}
								tokenMap[tokenSym].balance[acc] = append(tokenMap[tokenSym].balance[acc], ret)
								retn, _ := strconv.ParseInt(ret, 10, 32)
								tokenMap[tokenSym].supply = int(math.Max(float64(tokenMap[tokenSym].supply), float64(retn)))
							}
							tokenMutex.Unlock()
							break
						} else if r.Receipts[i].FuncName == "token721.iost/create" {
							args := make([]any, 3)
							err := json.Unmarshal([]byte(r.Receipts[i].Content), &args)
							if err != nil {
								continue
							}
							ilog.Debugf("got receipt %v %v", r.Receipts[i], args)
							tokenMutex.Lock()
							tokenSym := args[0].(string)
							issuer := args[1].(string)
							tokenList = append(tokenList, tokenSym)
							tokenMap[tokenSym] = &token721Info{
								sym:     tokenSym,
								issuer:  issuer,
								balance: make(map[string][]string),
								acclist: []string{},
								supply:  0,
							}
							tokenMutex.Unlock()
							break
						}
					}
				}
				if counter%1000 == 0 {
					ilog.Warnf("check %v transaction, %v successful, %v failed. channel size %v", counter, counter-failedCounter, failedCounter, len(hashCh))
				}
				if len(hashCh) > 3*tps*int(itest.Timeout.Seconds()) {
					ilog.Infof("hash ch size too large %v", len(hashCh))
				}
			}
		}(hashCh)
	}

	check := c.Bool("check")
	contractName := "token721.iost"
	for {
		trxs := make([]*itest.Transaction, 0)
		errList := []error{}
		tokenMutex.Lock()
		for num := 0; num < tps; num++ {

			tIndex := rand.Intn(2400)
			var abiName string
			switch {
			case tIndex <= 0 || len(tokenList) < 5:
				abiName = createToken721
				tokenSym := tokenPrefix + strconv.FormatInt(int64(tokenOffset), 10)
				tokenOffset++
				from := accounts[rand.Intn(len(accounts))]

				act0 := tx.NewAction("ram.iost", "buy", fmt.Sprintf(`["%v", "%v", %v]`, "admin", from.ID, 1000))
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act0, act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v", %v]`, tokenSym, from.ID, 100000000000))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 1000 || len(tokenMap[tokenList[0]].balance) < 10:
				abiName = issueToken721
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				if len(tokenMap[tokenList[0]].balance) < 10 {
					tokenSym = tokenList[0]
				}
				issuer := accountMap[tokenMap[tokenSym].issuer]
				to := accounts[rand.Intn(len(accounts))]
				act0 := tx.NewAction("ram.iost", "buy", fmt.Sprintf(`["%v", "%v", %v]`, "admin", issuer.ID, 1000))
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", issuer.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act0, act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
				acts := []*tx.Action{}
				for i := 0; i < issueNumber; i++ {
					acts = append(acts, tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v", "%v"]`, tokenSym, to.ID, "meta"+to.ID)))
				}
				tx1 := itest.NewTransaction(acts)
				trx, err = issuer.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 2000:
				abiName = transferToken721
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				if len(tokenMap[tokenSym].balance) == 0 {
					tokenSym = tokenList[0]
				}
				var from *itest.Account
				var tokenID string
				for k, v := range tokenMap[tokenSym].balance {
					from = accountMap[k]
					tokenID = v[0]
					break
				}
				to := accounts[rand.Intn(len(accounts))]
				act0 := tx.NewAction("ram.iost", "buy", fmt.Sprintf(`["%v", "%v", %v]`, "admin", from.ID, 1000))
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act0, act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v", "%v", "%v"]`, tokenSym, from.ID, to.ID, tokenID))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
					tokenMap[tokenSym].balance[from.ID] = tokenMap[tokenSym].balance[from.ID][1:]
					if len(tokenMap[tokenSym].balance[from.ID]) == 0 {
						delete(tokenMap[tokenSym].balance, from.ID)
					}
				}
			case tIndex <= 2100:
				abiName = balanceOfToken721
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				if len(tokenMap[tokenSym].balance) == 0 {
					tokenSym = tokenList[0]
				}
				from := accountMap[tokenMap[tokenSym].acclist[rand.Intn(len(tokenMap[tokenSym].acclist))]]
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v"]`, tokenSym, from.ID))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 2200:
				abiName = ownerOfToken721
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				if tokenMap[tokenSym].supply == 0 {
					tokenSym = tokenList[0]
				}
				from := accounts[rand.Intn(len(accounts))]
				tokenID := rand.Intn(tokenMap[tokenSym].supply)
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v"]`, tokenSym, tokenID))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 2300:
				abiName = tokenOfOwnerToken721
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				if len(tokenMap[tokenSym].balance) == 0 {
					tokenSym = tokenList[0]
				}
				var from *itest.Account
				var idx int
				for k, v := range tokenMap[tokenSym].balance {
					from = accountMap[k]
					idx = rand.Intn(len(v))
					break
				}
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v", %v]`, tokenSym, from.ID, idx))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 2400:
				abiName = tokenMetadataToken721
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				if tokenMap[tokenSym].supply == 0 {
					tokenSym = tokenList[0]
				}
				from := accounts[rand.Intn(len(accounts))]
				tokenID := rand.Intn(tokenMap[tokenSym].supply)
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v"]`, tokenSym, tokenID))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			}
		}
		tokenMutex.Unlock()
		hashList, tmpList := it.SendTransactionN(trxs, false)
		errList = append(errList, tmpList...)
		ilog.Warnf("Send %v trxs, got %v hash, %v err", len(trxs), len(hashList), len(errList))

		if check {
			expire := time.Now().Add(itest.Timeout)
			for _, hash := range hashList {
				select {
				case hashCh <- &hashItem{hash: hash, expire: expire}:
				case <-time.After(1 * time.Millisecond):
				}
			}
		}

		select {
		case <-sig:
			return fmt.Errorf("signal %v", sig)
		case <-ticker.C:
		}

		counter++
		slotTotal += len(trxs)
		if counter == 10 {
			total += slotTotal
			currentTps := float64(slotTotal) / time.Since(slotStartTime).Seconds()
			averageTps := float64(total) / time.Since(startTime).Seconds()
			ilog.Warnf("Current tps %v, Average tps %v, Total tx %v, token num %v", currentTps, averageTps, total, len(tokenList))
			counter = 0
			slotTotal = 0
			slotStartTime = time.Now()
		}
	}
}

BenchmarkToken721Action is the action of benchmark.

View Source
var BenchmarkToken721Command = cli.Command{
	Name:      "benchmarkToken721",
	ShortName: "benchT721",
	Usage:     "Run token benchmark by given tps",
	Flags:     BenchmarkToken721Flags,
	Action:    BenchmarkToken721Action,
}

BenchmarkToken721Command is the subcommand for benchmark.

View Source
var BenchmarkToken721Flags = []cli.Flag{
	cli.IntFlag{
		Name:  "tps",
		Value: 100,
		Usage: "The expected ratio of transactions per second",
	},
	cli.BoolFlag{
		Name:  "check",
		Usage: "if check receipt",
	},
}

BenchmarkToken721Flags is the list of flags for benchmark.

View Source
var BenchmarkTokenAction = func(c *cli.Context) error {
	itest.Interval = 1000 * time.Millisecond
	itest.InitAmount = "1000"
	itest.InitPledge = "1000"
	itest.InitRAM = "3000"
	logger := ilog.New()
	fileWriter := ilog.NewFileWriter(c.GlobalString("log"))
	fileWriter.SetLevel(ilog.LevelInfo)
	logger.AddWriter(fileWriter)
	ilog.InitLogger(logger)

	it, err := itest.Load(c.GlobalString("keys"), c.GlobalString("config"))
	if err != nil {
		return err
	}
	accountFile := c.GlobalString("account")
	t0 := time.Now()
	accounts, err := itest.LoadAccounts(accountFile)
	if err != nil {
		if err := AccountCaseAction(c); err != nil {
			return err
		}
		if accounts, err = itest.LoadAccounts(accountFile); err != nil {
			return err
		}
	}
	t1 := time.Now()
	ilog.Warnf("load account time: %v, got %v", float64(t1.UnixNano()-t0.UnixNano())/1e9, len(accounts))
	accountMap := make(map[string]*itest.Account)
	for _, acc := range accounts {
		accountMap[acc.ID] = acc
	}
	tps := c.Int("tps")

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	startTime := time.Now()
	ticker := time.NewTicker(time.Second)
	counter := 0
	total := 0
	slotTotal := 0
	slotStartTime := startTime

	tokenList := []string{"iost"}
	tokenMap := make(map[string]*tokenInfo)
	tokenMap["iost"] = &tokenInfo{
		sym:     "iost",
		issuer:  "",
		balance: make(map[string]float64),
		acclist: make([]string, 0),
	}
	for _, acc := range accounts {
		tokenMap["iost"].balance[acc.ID] = acc.Balance()
		tokenMap["iost"].acclist = append(tokenMap["iost"].acclist, acc.ID)
	}
	tokenPrefix := "t" + strconv.FormatInt(time.Now().UnixNano(), 10)[14:]
	checkReceiptConcurrent := 64
	tokenOffset := 0
	var tokenMutex sync.Mutex

	hashCh := make(chan *hashItem, 4*tps*int(itest.Timeout.Seconds()))
	for c := 0; c < checkReceiptConcurrent; c++ {
		go func(hashCh chan *hashItem) {
			counter := 0
			failedCounter := 0
			for item := range hashCh {
				client := it.GetClients()[rand.Intn(len(it.GetClients()))]
				r, err := client.CheckTransactionWithTimeout(item.hash, item.expire)
				counter++
				if err != nil {
					ilog.Errorf("check transaction failed, %v", err)
					failedCounter++
				} else {
					for i := 0; i < len(r.Receipts); i++ {
						if r.Receipts[i].FuncName == "token.iost/issue" {
							args := make([]string, 3)
							err := json.Unmarshal([]byte(r.Receipts[i].Content), &args)
							if err != nil {
								continue
							}
							ilog.Debugf("got receipt %v %v", r.Receipts[i], args)
							tokenMutex.Lock()
							tokenSym := args[0]
							if !strings.HasPrefix(tokenSym, tokenPrefix) {
								tokenMutex.Unlock()
								continue
							}
							acc := args[1]
							amountStr := args[2]
							amount, _ := strconv.ParseFloat(amountStr, 32)
							if _, ok := tokenMap[tokenSym].balance[acc]; !ok {
								tokenMap[tokenSym].acclist = append(tokenMap[tokenSym].acclist, acc)
							}
							tokenMap[tokenSym].balance[acc] += amount
							tokenMutex.Unlock()
							break
						} else if r.Receipts[i].FuncName == "token.iost/create" {
							args := make([]any, 4)
							err := json.Unmarshal([]byte(r.Receipts[i].Content), &args)
							if err != nil {
								continue
							}
							ilog.Debugf("got receipt %v %v", r.Receipts[i], args)
							tokenMutex.Lock()
							tokenSym := args[0].(string)
							issuer := args[1].(string)
							tokenList = append(tokenList, tokenSym)
							tokenMap[tokenSym] = &tokenInfo{
								sym:     tokenSym,
								issuer:  issuer,
								balance: make(map[string]float64),
								acclist: []string{},
							}
							tokenMutex.Unlock()
							break
						}
					}
				}
				if counter%1000 == 0 {
					ilog.Warnf("check %v transaction, %v successful, %v failed.", counter, counter-failedCounter, failedCounter)
				}
				if len(hashCh) > 3*tps*int(itest.Timeout.Seconds()) {
					ilog.Infof("hash ch size too large %v", len(hashCh))
				}
			}
		}(hashCh)
	}

	check := c.Bool("check")
	contractName := "token.iost"
	for {
		trxs := make([]*itest.Transaction, 0)
		errList := []error{}
		tokenMutex.Lock()
		for num := 0; num < tps; num++ {

			tIndex := rand.Intn(10000)
			var abiName string
			switch {
			case tIndex <= 0 || len(tokenList) < 5:
				abiName = createToken
				tokenSym := tokenPrefix + strconv.FormatInt(int64(tokenOffset), 10)
				tokenOffset++
				from := accounts[rand.Intn(len(accounts))]
				decimal := rand.Intn(5) + 2

				act0 := tx.NewAction("ram.iost", "buy", fmt.Sprintf(`["%v", "%v", %v]`, "admin", from.ID, 10000))
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act0, act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v", %v, %v]`, tokenSym, from.ID, 100000000000, fmt.Sprintf(`{"decimal": %v}`, decimal)))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 10:
				abiName = supplyToken
				ilog.Infof("supply")
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				from := accounts[rand.Intn(len(accounts))]
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v"]`, tokenSym))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)

				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 20:
				abiName = totalSupplyToken
				ilog.Infof("total supply")
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				from := accounts[rand.Intn(len(accounts))]
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v"]`, tokenSym))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 120:
				abiName = balanceOfToken
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				from := accounts[rand.Intn(len(accounts))]
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v"]`, tokenSym, from.ID))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 220:
				abiName = destroyToken
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				if len(tokenMap[tokenSym].balance) == 0 {
					tokenSym = "iost"
				}
				from := accountMap[tokenMap[tokenSym].acclist[rand.Intn(len(tokenMap[tokenSym].acclist))]]
				balance := tokenMap[tokenSym].balance[from.ID]
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				amount := math.Max(float64(rand.Intn(int(math.Max(balance, 1))))/100.0, 0.01)
				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v", "%v"]`, tokenSym, from.ID, amount))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
					tokenMap[tokenSym].balance[from.ID] -= amount
				}
			case tIndex <= 1000:
				abiName = issueToken
				if len(tokenList) == 1 {
					break
				}
				tokenSym := tokenList[1+rand.Intn(len(tokenList)-1)]
				issuer := accountMap[tokenMap[tokenSym].issuer]
				to := accounts[rand.Intn(len(accounts))]
				act0 := tx.NewAction("ram.iost", "buy", fmt.Sprintf(`["%v", "%v", %v]`, "admin", issuer.ID, 1000))
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", issuer.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act0, act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
				amount := 1000 + 1000*rand.Float64()
				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v", "%v"]`, tokenSym, to.ID, int64(amount)))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = issuer.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}
			case tIndex <= 1100:
				abiName = transferFreezeToken
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				if len(tokenMap[tokenSym].balance) == 0 {
					tokenSym = "iost"
				}
				from := accountMap[tokenMap[tokenSym].acclist[rand.Intn(len(tokenMap[tokenSym].acclist))]]
				to := accounts[rand.Intn(len(accounts))]
				balance := tokenMap[tokenSym].balance[from.ID]
				act0 := tx.NewAction("ram.iost", "buy", fmt.Sprintf(`["%v", "%v", %v]`, "admin", from.ID, 10000))
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act0, act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				ftime := time.Now().UnixNano() + int64(rand.Intn(100))*1e9
				amount := math.Max(float64(rand.Intn(int(math.Max(balance, 1))))/100.0, 0.01)
				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v", "%v", "%v", %v, "%v"]`, tokenSym, from.ID, to.ID, amount, ftime, ""))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
					tokenMap[tokenSym].balance[from.ID] -= amount
				}
			default:
				abiName = transferToken
				tokenSym := tokenList[rand.Intn(len(tokenList))]
				if len(tokenMap[tokenSym].balance) == 0 {
					tokenSym = "iost"
				}
				from := accountMap[tokenMap[tokenSym].acclist[rand.Intn(len(tokenMap[tokenSym].acclist))]]
				to := accounts[rand.Intn(len(accounts))]
				balance := tokenMap[tokenSym].balance[from.ID]
				act0 := tx.NewAction("ram.iost", "buy", fmt.Sprintf(`["%v", "%v", %v]`, "admin", from.ID, 100))
				act1 := tx.NewAction("gas.iost", "pledge", fmt.Sprintf(`["%v", "%v", "%v"]`, "admin", from.ID, 10))
				tx0 := itest.NewTransaction([]*tx.Action{act0, act1})
				trx, err := it.GetDefaultAccount().Sign(tx0)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
				}

				amount := math.Max(float64(rand.Intn(int(math.Max(balance, 1))))/100.0, 0.01)
				act1 = tx.NewAction(contractName, abiName, fmt.Sprintf(`["%v", "%v", "%v", "%v", "%v"]`, tokenSym, from.ID, to.ID, amount, ""))
				tx1 := itest.NewTransaction([]*tx.Action{act1})
				trx, err = from.Sign(tx1)
				if err != nil {
					errList = append(errList, err)
				} else {
					trxs = append(trxs, trx)
					tokenMap[tokenSym].balance[from.ID] -= amount
				}
			}
		}
		tokenMutex.Unlock()
		hashList, tmpList := it.SendTransactionN(trxs, false)
		errList = append(errList, tmpList...)
		ilog.Warnf("Send %v trxs, got %v hash, %v err", len(trxs), len(hashList), len(errList))

		if check {
			expire := time.Now().Add(itest.Timeout)
			for _, hash := range hashList {
				select {
				case hashCh <- &hashItem{hash: hash, expire: expire}:
				case <-time.After(1 * time.Millisecond):
				}
			}
		}

		select {
		case <-sig:
			return fmt.Errorf("signal %v", sig)
		case <-ticker.C:
		}

		counter++
		slotTotal += len(trxs)
		if counter == 10 {
			total += slotTotal
			currentTps := float64(slotTotal) / time.Since(slotStartTime).Seconds()
			averageTps := float64(total) / time.Since(startTime).Seconds()
			ilog.Warnf("Current tps %v, Average tps %v, Total tx %v, token num %v", currentTps, averageTps, total, len(tokenList))
			counter = 0
			slotTotal = 0
			slotStartTime = time.Now()
		}
	}
}

BenchmarkTokenAction is the action of benchmark.

View Source
var BenchmarkTokenCommand = cli.Command{
	Name:      "benchmarkToken",
	ShortName: "benchT",
	Usage:     "Run token benchmark by given tps",
	Flags:     BenchmarkTokenFlags,
	Action:    BenchmarkTokenAction,
}

BenchmarkTokenCommand is the subcommand for benchmark.

View Source
var BenchmarkTokenFlags = []cli.Flag{
	cli.IntFlag{
		Name:  "tps",
		Value: 50,
		Usage: "The expected ratio of transactions per second",
	},
	cli.BoolFlag{
		Name:  "check",
		Usage: "if check receipt",
	},
}

BenchmarkTokenFlags is the list of flags for benchmark.

View Source
var BonusCaseAction = func(c *cli.Context) error {
	acc := c.GlobalString("aname")
	keysfile := c.GlobalString("keys")
	configfile := c.GlobalString("config")

	it, err := itest.Load(keysfile, configfile)
	if err != nil {
		return err
	}

	data, _, number, err := it.GetContractStorage("token.iost", "TB"+acc, "contribute")
	if err != nil {
		return err
	}
	ilog.Debugf("%v contribute = %v, number = %v", acc, data, number)

	contribute, err := strconv.ParseInt(data, 10, 64)
	if err != nil {
		return err
	}
	data1, _, _, err := it.GetContractStorage("bonus.iost", "blockContrib", "")
	if err != nil {
		return err
	}
	ratef, err := strconv.ParseFloat(strings.Trim(data1, "\""), 64)
	if err != nil {
		return err
	}

	cnt, err := countBlockProducedBy(it, acc, number)
	if cnt == 0 || err != nil {
		return err
	}

	rate := int64(ratef * 1e8)
	if contribute == cnt*rate {
		ilog.Infof("success: contribute = %v, cnt*rate = %v", contribute, cnt*rate)
		return nil
	} else if contribute < cnt*rate && contribute*103 > cnt*rate*100 {
		ilog.Infof("success contribute is nearly equal to cnt*rate: contribute = %v, cnt*rate = %v", contribute, cnt*rate)
		return nil
	}
	return fmt.Errorf("check contribute failed: contribute = %v, cnt = %v, rate = %v(%v)", contribute, cnt, rate, data1)
}

BonusCaseAction is the action of Bonus test case

View Source
var BonusCaseCommand = cli.Command{
	Name:      "bonus_case",
	ShortName: "b_case",
	Usage:     "run bonus test case",
	Action:    BonusCaseAction,
}

BonusCaseCommand is the command of account test case

Command is the command of run

View Source
var CommonVoteCaseAction = func(c *cli.Context) error {
	afile := c.String("account")
	keysfile := c.GlobalString("keys")
	configfile := c.GlobalString("newVoteConfig")
	it, err := itest.Load(keysfile, configfile)
	if err != nil {
		return err
	}
	client := it.GetClients()[0]
	accounts, err := itest.LoadAccounts(afile)
	if err != nil {
		return err
	}

	newVoteConfig := make(map[string]any)
	newVoteConfig["resultNumber"] = 2
	newVoteConfig["minVote"] = 10
	newVoteConfig["options"] = []string{"option1", "option2", "option3", "option4"}
	newVoteConfig["anyOption"] = false
	newVoteConfig["freezeTime"] = 0
	bank := it.GetDefaultAccount()
	hash, err := it.CallActionWithRandClient(it.GetDefaultAccount(), "vote.iost", "newVote", bank.ID, "test vote", newVoteConfig)
	if err != nil {
		return err
	}
	receipt, err := client.GetReceipt(hash)
	if err != nil {
		return err
	}
	js, err := simplejson.NewJson([]byte(receipt.Returns[0]))
	if err != nil {
		return err
	}
	voteID, err := js.GetIndex(0).String()
	if err != nil {
		return err
	}
	fmt.Println("vote id is", voteID)
	allArgs := make([][]any, 0)
	allArgs = append(allArgs, []any{voteID, accounts[1].ID, "option3", "5"})
	allArgs = append(allArgs, []any{voteID, accounts[1].ID, "option3", "5"})
	allArgs = append(allArgs, []any{voteID, accounts[1].ID, "option1", "20"})
	allArgs = append(allArgs, []any{voteID, accounts[0].ID, "option3", "100"})
	var callingAccounts = []*itest.Account{accounts[1], accounts[1], accounts[1], accounts[0]}

	res := make(chan any)
	go func() {
		for idx := range allArgs {
			go func(i int, res chan any) {
				_, err := it.CallActionWithRandClient(callingAccounts[i], "vote.iost", "vote", allArgs[i]...)
				res <- err
			}(idx, res)
		}
	}()
	for range allArgs {
		switch value := (<-res).(type) {
		case error:
			return value
		}
	}

	checkReturn := func(actionName string, expected string, args ...any) error {
		hash, err := client.CallAction(true, bank, "vote.iost", actionName, args...)
		if err != nil {
			return err
		}
		receipt, err = client.GetReceipt(hash)
		if err != nil {
			return err
		}
		js, err := simplejson.NewJson([]byte(receipt.Returns[0]))
		if err != nil {
			return err
		}
		result, err := js.GetIndex(0).String()
		if err != nil {
			return err
		}
		if result != expected {
			return fmt.Errorf("invalid return %v, expect %v", result, expected)
		}
		return nil
	}
	res2 := make(chan error)
	go func() {
		res2 <- checkReturn("getResult", `[{"option":"option3","votes":"110"},{"option":"option1","votes":"20"}]`, voteID)
	}()
	go func() {
		res2 <- checkReturn("getOption", `{"votes":"110","deleted":false,"clearTime":-1}`, voteID, "option3")
	}()

	for i := 0; i < 2; i++ {
		if err := <-res2; err != nil {
			return err
		}
	}
	return nil
}

CommonVoteCaseAction is the action of vote test case

View Source
var CommonVoteCaseCommand = cli.Command{
	Name:      "common_vote_case",
	ShortName: "cv_case",
	Usage:     "run common VoteProducer test case",
	Flags:     CommonVoteCaseFlags,
	Action:    CommonVoteCaseAction,
}

CommonVoteCaseCommand is the command of common vote test case

View Source
var CommonVoteCaseFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "account, a",
		Value: "accounts.json",
		Usage: "load accounts from `FILE`",
	},
}

CommonVoteCaseFlags is the flags of vote test case

View Source
var ContractCaseAction = func(c *cli.Context) error {
	afile := c.String("account")
	output := c.String("output")
	tnum := c.Int("number")
	keysfile := c.GlobalString("keys")
	configfile := c.GlobalString("config")
	codefile := c.GlobalString("code")
	abifile := c.GlobalString("abi")
	memoSize := c.Int("memo")

	it, err := itest.Load(keysfile, configfile)
	if err != nil {
		return err
	}

	contract, err := itest.LoadContract(codefile, abifile)
	if err != nil {
		return err
	}

	accounts, err := itest.LoadAccounts(afile)
	if err != nil {
		return err
	}

	cid, err := it.SetContract(contract)
	if err != nil {
		return err
	}

	if _, err := it.ContractTransferN(cid, tnum, accounts, memoSize, true); err != nil {
		return err
	}

	if err := it.CheckAccounts(accounts); err != nil {
		return err
	}

	if err := itest.DumpAccounts(accounts, output); err != nil {
		return err
	}

	return nil
}

ContractCaseAction is the action of contract test case

View Source
var ContractCaseCommand = cli.Command{
	Name:      "contract_case",
	ShortName: "c_case",
	Usage:     "run contract test case",
	Flags:     ContractCaseFlags,
	Action:    ContractCaseAction,
}

ContractCaseCommand is the command of contract test case

View Source
var ContractCaseFlags = []cli.Flag{
	cli.IntFlag{
		Name:  "number, n",
		Value: 1000,
		Usage: "number of transaction",
	},
	cli.StringFlag{
		Name:  "account, a",
		Value: "accounts.json",
		Usage: "load accounts from `FILE`",
	},
	cli.StringFlag{
		Name:  "output, o",
		Value: "accounts.json",
		Usage: "output of account information",
	},
	cli.IntFlag{
		Name:  "memo, m",
		Value: 0,
		Usage: "The size of a random memo message that would be contained in the transaction",
	},
}

ContractCaseFlags ...

View Source
var Flags = []cli.Flag{
	cli.StringFlag{
		Name:  "keys, k",
		Value: "",
		Usage: "Load keys from `FILE`",
	},
	cli.StringFlag{
		Name:  "config, c",
		Value: "",
		Usage: "Load itest configuration from `FILE`",
	},
	cli.StringFlag{
		Name:  "code",
		Value: "",
		Usage: "Load contract code from `FILE`",
	},
	cli.StringFlag{
		Name:  "abi",
		Value: "",
		Usage: "Load contract abi from `FILE`",
	},
	cli.StringFlag{
		Name:  "account, a",
		Value: "accounts.json",
		Usage: "The account file that itest would load from if exists",
	},
	cli.IntFlag{
		Name:  "anum",
		Value: 100,
		Usage: "The number of accounts to generated if no given account file",
	},
	cli.StringFlag{
		Name:  "aname",
		Value: "producer000",
		Usage: "The account name to check/run actions",
	},
	cli.StringFlag{
		Name:  "log, l",
		Value: "itest_logs",
		Usage: "log file path",
	},
}

Flags is the flags of run command

View Source
var TransferCaseAction = func(c *cli.Context) error {
	afile := c.GlobalString("account")
	output := c.String("output")
	tnum := c.Int("number")
	keysfile := c.GlobalString("keys")
	configfile := c.GlobalString("config")
	memoSize := c.Int("memo")

	it, err := itest.Load(keysfile, configfile)
	if err != nil {
		return err
	}

	accounts, err := itest.LoadAccounts(afile)
	if err != nil {
		return err
	}

	if _, err := it.TransferN(tnum, accounts, memoSize, true); err != nil {
		return err
	}

	if err := it.CheckAccounts(accounts); err != nil {
		return err
	}

	if err := itest.DumpAccounts(accounts, output); err != nil {
		return err
	}

	return nil
}

TransferCaseAction is the action of transfer test case

View Source
var TransferCaseCommand = cli.Command{
	Name:      "transfer_case",
	ShortName: "t_case",
	Usage:     "run transfer test case",
	Flags:     TransferCaseFlags,
	Action:    TransferCaseAction,
}

TransferCaseCommand is the command of transfer test case

View Source
var TransferCaseFlags = []cli.Flag{
	cli.IntFlag{
		Name:  "number, n",
		Value: 1000,
		Usage: "number of transaction",
	},
	cli.StringFlag{
		Name:  "output, o",
		Value: "accounts.json",
		Usage: "output of account information",
	},
	cli.IntFlag{
		Name:  "memo, m",
		Value: 0,
		Usage: "The size of a random memo message that would be contained in the transaction",
	},
}

TransferCaseFlags is the flags of transfer test case

View Source
var VoteCaseAction = func(c *cli.Context) error {
	afile := c.String("account")
	output := c.String("output")
	tnum := c.Int("number")
	punm := c.Int("pnumber")
	keysfile := c.GlobalString("keys")
	configfile := c.GlobalString("config")

	it, err := itest.Load(keysfile, configfile)
	if err != nil {
		return err
	}

	accounts, err := itest.LoadAccounts(afile)
	if err != nil {
		return err
	}

	if err := it.VoteN(tnum, punm, accounts); err != nil {
		return err
	}

	if err := it.CheckAccounts(accounts); err != nil {
		return err
	}

	if err := itest.DumpAccounts(accounts, output); err != nil {
		return err
	}

	return nil
}

VoteCaseAction is the action of vote test case

View Source
var VoteCaseCommand = cli.Command{
	Name:      "vote_case",
	ShortName: "v_case",
	Usage:     "run VoteProducer test case",
	Flags:     VoteCaseFlags,
	Action:    VoteCaseAction,
}

VoteCaseCommand is the command of vote test case

View Source
var VoteCaseFlags = []cli.Flag{
	cli.IntFlag{
		Name:  "number, n",
		Value: 1000,
		Usage: "number of transaction",
	},
	cli.IntFlag{
		Name:  "pnumber, pn",
		Value: 1,
		Usage: "number of producer",
	},
	cli.StringFlag{
		Name:  "account, a",
		Value: "accounts.json",
		Usage: "load accounts from `FILE`",
	},
	cli.StringFlag{
		Name:  "output, o",
		Value: "accounts.json",
		Usage: "output of account information",
	},
}

VoteCaseFlags is the flags of vote test case

View Source
var VoteNodeCaseAction = func(c *cli.Context) error {
	tnum := c.Int("number")
	unvote := c.Bool("unvote")
	keysfile := c.GlobalString("keys")
	configfile := c.GlobalString("config")
	afile := c.GlobalString("account")

	it, err := itest.Load(keysfile, configfile)
	if err != nil {
		return err
	}

	accounts, err := itest.LoadAccounts(afile)
	if err != nil {
		return err
	}

	if unvote {
		if err := it.CancelVoteNode(tnum, accounts); err != nil {
			return err
		}
	} else {
		if err := it.VoteNode(tnum, accounts); err != nil {
			return err
		}
	}

	return nil
}

VoteNodeCaseAction is the action of vote test case

View Source
var VoteNodeCaseCommand = cli.Command{
	Name:      "vote_node_case",
	ShortName: "n_case",
	Usage:     "run a test to vote or unvote for node",
	Flags:     VoteNodeCaseFlags,
	Action:    VoteNodeCaseAction,
}

VoteNodeCaseCommand is vote or unvote for the test of the authentication node

View Source
var VoteNodeCaseFlags = []cli.Flag{
	cli.IntFlag{
		Name:  "number, n",
		Value: 0,
		Usage: "number of vote",
	},
	cli.BoolFlag{
		Name:  "unvote, u",
		Usage: "Cancel vote based on configuration file",
	},
}

VoteNodeCaseFlags is the flags of vote test case

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL