Пример #1
0
/*
 * Каждые 2 недели собираем инфу о голосах за % и создаем тр-ию, которая
 * попадет в DC сеть только, если мы окажемся генератором блока
 * */
func PctGenerator(chBreaker chan bool, chAnswer chan string) {
	defer func() {
		if r := recover(); r != nil {
			log.Error("daemon Recovered", r)
			panic(r)
		}
	}()

	const GoroutineName = "PctGenerator"
	d := new(daemon)
	d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName)
	if d.DCDB == nil {
		return
	}
	d.goRoutineName = GoroutineName
	d.chAnswer = chAnswer
	d.chBreaker = chBreaker
	if utils.Mobile() {
		d.sleepTime = 3600
	} else {
		d.sleepTime = 60
	}
	if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) {
		return
	}
	d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName)
	if d.DCDB == nil {
		return
	}

	err = d.notMinerSetSleepTime(1800)
	if err != nil {
		log.Error("%v", err)
		return
	}

BEGIN:
	for {
		log.Info(GoroutineName)
		MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())}

		// проверим, не нужно ли нам выйти из цикла
		if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) {
			break BEGIN
		}

		err, restart := d.dbLock()
		if restart {
			break BEGIN
		}
		if err != nil {
			if d.dPrintSleep(err, d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}

		blockId, err := d.GetBlockId()
		if err != nil {
			if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		if blockId == 0 {
			if d.unlockPrintSleep(utils.ErrInfo("blockId == 0"), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}

		_, _, myMinerId, _, _, _, err := d.TestBlock()
		if err != nil {
			if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		// а майнер ли я ?
		if myMinerId == 0 {
			if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		variables, err := d.GetAllVariables()
		curTime := utils.Time()

		// проверим, прошло ли 2 недели с момента последнего обновления pct
		pctTime, err := d.Single("SELECT max(time) FROM pct").Int64()
		if err != nil {
			if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		if curTime-pctTime > variables.Int64["new_pct_period"] {

			// берем все голоса miner_pct
			pctVotes := make(map[int64]map[string]map[string]int64)
			rows, err := d.Query("SELECT currency_id, pct, count(user_id) as votes FROM votes_miner_pct GROUP BY currency_id, pct ORDER BY currency_id, pct ASC")
			if err != nil {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			for rows.Next() {
				var currency_id, votes int64
				var pct string
				err = rows.Scan(&currency_id, &pct, &votes)
				if err != nil {
					rows.Close()
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				log.Info("%v", "newpctcurrency_id", currency_id, "pct", pct, "votes", votes)
				if len(pctVotes[currency_id]) == 0 {
					pctVotes[currency_id] = make(map[string]map[string]int64)
				}
				if len(pctVotes[currency_id]["miner_pct"]) == 0 {
					pctVotes[currency_id]["miner_pct"] = make(map[string]int64)
				}
				pctVotes[currency_id]["miner_pct"][pct] = votes
			}
			rows.Close()

			// берем все голоса user_pct
			rows, err = d.Query("SELECT currency_id, pct, count(user_id) as votes FROM votes_user_pct GROUP BY currency_id, pct ORDER BY currency_id, pct ASC")
			if err != nil {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			for rows.Next() {
				var currency_id, votes int64
				var pct string
				err = rows.Scan(&currency_id, &pct, &votes)
				if err != nil {
					rows.Close()
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				log.Info("%v", "currency_id", currency_id, "pct", pct, "votes", votes)
				if len(pctVotes[currency_id]) == 0 {
					pctVotes[currency_id] = make(map[string]map[string]int64)
				}
				if len(pctVotes[currency_id]["user_pct"]) == 0 {
					pctVotes[currency_id]["user_pct"] = make(map[string]int64)
				}
				pctVotes[currency_id]["user_pct"][pct] = votes
			}
			rows.Close()

			newPct := make(map[string]map[string]map[string]string)
			newPct["currency"] = make(map[string]map[string]string)
			var userMaxKey int64
			PctArray := utils.GetPctArray()

			log.Info("%v", "pctVotes", pctVotes)
			for currencyId, data := range pctVotes {

				currencyIdStr := utils.Int64ToStr(currencyId)
				// определяем % для майнеров
				pctArr := utils.MakePctArray(data["miner_pct"])
				log.Info("%v", "pctArrminer_pct", pctArr, currencyId)
				key := utils.GetMaxVote(pctArr, 0, 390, 100)
				log.Info("%v", "key", key)
				if len(newPct["currency"][currencyIdStr]) == 0 {
					newPct["currency"][currencyIdStr] = make(map[string]string)
				}
				newPct["currency"][currencyIdStr]["miner_pct"] = utils.GetPctValue(key)

				// определяем % для юзеров
				pctArr = utils.MakePctArray(data["user_pct"])
				log.Info("%v", "pctArruser_pct", pctArr, currencyId)

				log.Info("%v", "newPct", newPct)
				pctY := utils.ArraySearch(newPct["currency"][currencyIdStr]["miner_pct"], PctArray)
				log.Info("%v", "newPct[currency][currencyIdStr][miner_pct]", newPct["currency"][currencyIdStr]["miner_pct"])
				log.Info("%v", "PctArray", PctArray)
				log.Info("%v", "miner_pct $pct_y=", pctY)
				maxUserPctY := utils.Round(utils.StrToFloat64(pctY)/2, 2)
				userMaxKey = utils.FindUserPct(int(maxUserPctY))
				log.Info("%v", "maxUserPctY", maxUserPctY, "userMaxKey", userMaxKey, "currencyIdStr", currencyIdStr)
				// отрезаем лишнее, т.к. поиск идет ровно до макимального возможного, т.е. до miner_pct/2
				pctArr = utils.DelUserPct(pctArr, userMaxKey)
				log.Info("%v", "pctArr", pctArr)

				key = utils.GetMaxVote(pctArr, 0, userMaxKey, 100)
				log.Info("%v", "data[user_pct]", data["user_pct"])
				log.Info("%v", "pctArr", pctArr)
				log.Info("%v", "userMaxKey", userMaxKey)
				log.Info("%v", "key", key)
				newPct["currency"][currencyIdStr]["user_pct"] = utils.GetPctValue(key)
				log.Info("%v", "user_pct", newPct["currency"][currencyIdStr]["user_pct"])
			}

			newPct_ := new(newPctType)
			newPct_.Currency = make(map[string]map[string]string)
			newPct_.Currency = newPct["currency"]
			newPct_.Referral = make(map[string]int64)
			refLevels := []string{"first", "second", "third"}
			for i := 0; i < len(refLevels); i++ {
				level := refLevels[i]
				var votesReferral []map[int64]int64
				// берем все голоса
				rows, err := d.Query("SELECT " + level + ", count(user_id) as votes FROM votes_referral GROUP BY " + level + " ORDER BY " + level + " ASC ")
				if err != nil {
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				for rows.Next() {
					var level_, votes int64
					err = rows.Scan(&level_, &votes)
					if err != nil {
						rows.Close()
						if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
							break BEGIN
						}
						continue BEGIN
					}
					votesReferral = append(votesReferral, map[int64]int64{level_: votes})
				}
				rows.Close()
				newPct_.Referral[level] = (utils.GetMaxVote(votesReferral, 0, 30, 10))
			}
			jsonData, err := json.Marshal(newPct_)
			if err != nil {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}

			_, myUserId, _, _, _, _, err := d.TestBlock()
			forSign := fmt.Sprintf("%v,%v,%v,%s", utils.TypeInt("NewPct"), curTime, myUserId, jsonData)
			log.Debug("forSign = %v", forSign)
			binSign, err := d.GetBinSign(forSign, myUserId)
			log.Debug("binSign = %x", binSign)
			if err != nil {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			data := utils.DecToBin(utils.TypeInt("NewPct"), 1)
			data = append(data, utils.DecToBin(curTime, 4)...)
			data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(myUserId))...)
			data = append(data, utils.EncodeLengthPlusData(jsonData)...)
			data = append(data, utils.EncodeLengthPlusData([]byte(binSign))...)

			err = d.InsertReplaceTxInQueue(data)
			if err != nil {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}

			// и не закрывая main_lock переводим нашу тр-ию в verified=1, откатив все несовместимые тр-ии
			// таким образом у нас будут в блоке только актуальные голоса.
			// а если придет другой блок и станет verified=0, то эта тр-ия просто удалится.

			p := new(dcparser.Parser)
			p.DCDB = d.DCDB
			err = p.TxParser(utils.HexToBin(utils.Md5(data)), data, true)
			if err != nil {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
		}
		d.dbUnlock()

		if d.dSleep(d.sleepTime) {
			break BEGIN
		}
	}
	log.Debug("break BEGIN %v", GoroutineName)
}
Пример #2
0
func (c *Controller) StatisticVoting() (string, error) {

	var err error

	js := ""
	var divs []string

	/*
	 * Голосование за размер обещанной суммы
	 */
	rows, err := c.Query(c.FormatQuery(`SELECT currency_id, amount, count(user_id) as votes FROM votes_max_promised_amount GROUP BY currency_id, amount`))
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	defer rows.Close()
	maxPromisedAmountVotes := make(map[int64][]map[int64]int64)
	for rows.Next() {
		var currency_id, votes, amount int64
		err = rows.Scan(&currency_id, &amount, &votes)
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		maxPromisedAmountVotes[currency_id] = append(maxPromisedAmountVotes[currency_id], map[int64]int64{amount: votes})
	}

	for currencyId, arr := range maxPromisedAmountVotes {
		js += fmt.Sprintf("var max_promised_amounts_%d = [", currencyId)
		for _, data := range arr {
			for k, v := range data {
				js += fmt.Sprintf("[%v, %v],", k, v)
			}
		}
		js = js[:len(js)-1] + "];\n"
		divs = append(divs, fmt.Sprintf("max_promised_amounts_%d", currencyId))
	}

	totalCountCurrencies, err := c.Single("SELECT count(id) FROM currency").Int64()
	if err != nil {
		return "", utils.ErrInfo(err)
	}

	newMaxPromisedAmounts := make(map[int64]int64)
	//array []map[int64]int64, min, max, step int64
	for currencyId, data := range maxPromisedAmountVotes {
		newMaxPromisedAmounts[currencyId] = utils.GetMaxVote(data, 0, totalCountCurrencies, 10)
	}

	/*
	 * Голосование за кол-во валют в обещанных суммах
	 */
	rows, err = c.Query(c.FormatQuery(`SELECT currency_id, count, count(user_id) as votes FROM votes_max_other_currencies GROUP BY  currency_id, count`))
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	defer rows.Close()
	maxOtherCurrenciesVotes := make(map[int64][]map[int64]int64)
	for rows.Next() {
		var currency_id, count, votes int64
		err = rows.Scan(&currency_id, &count, &votes)
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		maxOtherCurrenciesVotes[currency_id] = append(maxOtherCurrenciesVotes[currency_id], map[int64]int64{count: votes})
	}

	log.Debug("maxOtherCurrenciesVotes", maxOtherCurrenciesVotes)
	newMaxOtherCurrencies := make(map[int64]int64)
	for currencyId, arr := range maxOtherCurrenciesVotes {
		newMaxOtherCurrencies[currencyId] = utils.GetMaxVote(arr, 0, totalCountCurrencies, 10)
		js += fmt.Sprintf("var max_other_currencies_votes_%d = [", currencyId)
		for _, data := range arr {
			log.Debug("data", data)
			for k, v := range data {
				js += fmt.Sprintf("[%v, %v],", k, v)
			}
		}
		js = js[:len(js)-1] + "];\n"
		log.Debug("js", js)
		divs = append(divs, fmt.Sprintf("max_other_currencies_votes_%d", currencyId))
	}

	/*
	 * Голосование за ручное сокращение объема монет
	 * */
	// получаем кол-во обещанных сумм у разных юзеров по каждой валюте. start_time есть только у тех, у кого статус mining/repaid
	promisedAmount_, err := c.GetAll(`
			SELECT currency_id, count(user_id) as count
					FROM (
							SELECT currency_id, user_id
							FROM promised_amount
							WHERE start_time < ? AND
										 del_block_id = 0 AND
										 del_mining_block_id = 0 AND
										 status IN ('mining', 'repaid')
							GROUP BY  user_id, currency_id
							) as t1
					GROUP BY  currency_id
	`, -1, utils.Time()-c.Variables.Int64["min_hold_time_promise_amount"])
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	promisedAmount := make(map[string]string)
	for _, data := range promisedAmount_ {
		promisedAmount[data["currency_id"]] = data["count"]
	}

	// берем все голоса юзеров по данной валюте
	votesReduction := make(map[string]map[string]string)
	votesReduction_, err := c.GetAll(`
			SELECT currency_id,
					  	pct,
					     count(currency_id) as votes
			FROM votes_reduction
			WHERE time > ? AND
						 pct > 0
			GROUP BY currency_id, pct
	`, -1, utils.Time()-c.Variables.Int64["reduction_period"])
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	for _, data := range votesReduction_ {
		votesReduction[data["currency_id"]] = make(map[string]string)
		votesReduction[data["currency_id"]][data["pct"]] = data["votes"]
	}

	/*
	 * Голосование за реф. бонусы
	 * */
	refLevels := []string{"first", "second", "third"}
	newReferralPct := make(map[string]int64)
	votesReferral := make(map[string][]map[int64]int64)
	for i := 0; i < len(refLevels); i++ {
		level := refLevels[i]
		// берем все голоса
		votesReferral_, err := c.GetAll(`
				SELECT `+level+`,
							  count(user_id) as votes
				FROM votes_referral
				GROUP BY  `+level+`
		`, -1)
		if err != nil {
			return "", utils.ErrInfo(err)
		}

		for _, data := range votesReferral_ {
			votesReferral[level] = append(votesReferral[level], map[int64]int64{utils.StrToInt64(data[level]): utils.StrToInt64(data["votes"])})
		}

		newReferralPct[level] = utils.GetMaxVote(votesReferral[level], 0, 30, 10)
	}

	for level, arr := range votesReferral {
		js += "var votes_referral_" + level + " = ["
		for _, data := range arr {
			for k, v := range data {
				js += fmt.Sprintf("[%v, %v],", k, v)
			}
		}
		js = js[:len(js)-1] + "];\n"
		divs = append(divs, "votes_referral_"+level)
	}

	/*
	 * Голосоваие за майнеркие и юзерские %
	 * */
	// берем все голоса miner_pct
	pctVotes := make(map[int64]map[string]map[string]int64)
	rows, err = c.Query("SELECT currency_id, pct, count(user_id) as votes FROM votes_miner_pct GROUP BY currency_id, pct ORDER BY currency_id, pct ASC")
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	defer rows.Close()
	for rows.Next() {
		var currency_id, votes int64
		var pct string
		err = rows.Scan(&currency_id, &pct, &votes)
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		log.Debug("newpctcurrency_id", currency_id, "pct", pct, "votes", votes)
		if len(pctVotes[currency_id]) == 0 {
			pctVotes[currency_id] = make(map[string]map[string]int64)
		}
		if len(pctVotes[currency_id]["miner_pct"]) == 0 {
			pctVotes[currency_id]["miner_pct"] = make(map[string]int64)
		}
		pctVotes[currency_id]["miner_pct"][pct] = votes
	}

	// берем все голоса user_pct
	rows, err = c.Query("SELECT currency_id, pct, count(user_id) as votes FROM votes_user_pct GROUP BY currency_id, pct ORDER BY currency_id, pct ASC")
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	defer rows.Close()
	for rows.Next() {
		var currency_id, votes int64
		var pct string
		err = rows.Scan(&currency_id, &pct, &votes)
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		log.Debug("currency_id", currency_id, "pct", pct, "votes", votes)
		if len(pctVotes[currency_id]) == 0 {
			pctVotes[currency_id] = make(map[string]map[string]int64)
		}
		if len(pctVotes[currency_id]["user_pct"]) == 0 {
			pctVotes[currency_id]["user_pct"] = make(map[string]int64)
		}
		pctVotes[currency_id]["user_pct"][pct] = votes
	}

	log.Debug("pctVotes", pctVotes)

	for currencyId, data := range pctVotes {
		currencyIdStr := utils.Int64ToStr(currencyId)
		divs = append(divs, "miner_pct_"+currencyIdStr)
		divs = append(divs, "user_pct_"+currencyIdStr)

		js += "var miner_pct_" + currencyIdStr + " = ["
		for k, v := range data["miner_pct"] {
			pctY := utils.Round((math.Pow(1+utils.StrToFloat64(k), 3600*24*365)-1)*100, 2)
			js += fmt.Sprintf("[%v, %v],", pctY, v)
		}
		js = js[:len(js)-1] + "];\n"

		js += "var user_pct_" + currencyIdStr + " = ["
		for k, v := range data["user_pct"] {
			pctY := utils.Round((math.Pow(1+utils.StrToFloat64(k), 3600*24*365)-1)*100, 2)
			js += fmt.Sprintf("[%v, %v],", pctY, v)
		}
		js = js[:len(js)-1] + "];\n"
	}

	newPct := make(map[string]map[string]string)
	newPctTpl := make(map[string]map[string]float64)
	var userMaxKey int64
	PctArray := utils.GetPctArray()

	log.Debug("pctVotes", pctVotes)
	for currencyId, data := range pctVotes {

		currencyIdStr := utils.Int64ToStr(currencyId)
		// определяем % для майнеров
		pctArr := utils.MakePctArray(data["miner_pct"])
		log.Debug("currencyIdStr:", currencyIdStr)
		log.Debug("miner_pct:", data["miner_pct"])
		log.Debug("pctArr:", pctArr)
		key := utils.GetMaxVote(pctArr, 0, 390, 100)
		log.Debug("key:", key)
		if len(newPct[currencyIdStr]) == 0 {
			newPct[currencyIdStr] = make(map[string]string)
		}
		newPct[currencyIdStr]["miner_pct"] = utils.GetPctValue(key)
		if len(newPctTpl[currencyIdStr]) == 0 {
			newPctTpl[currencyIdStr] = make(map[string]float64)
		}
		newPctTpl[currencyIdStr]["miner_pct"] = utils.Round((math.Pow(1+utils.StrToFloat64(utils.GetPctValue(key)), 3600*24*365)-1)*100, 2)

		// определяем % для юзеров
		pctArr = utils.MakePctArray(data["user_pct"])
		pctY := utils.ArraySearch(newPct[currencyIdStr]["miner_pct"], PctArray)
		maxUserPctY := utils.Round(utils.StrToFloat64(pctY)/2, 2)
		userMaxKey = utils.FindUserPct(int(maxUserPctY))
		// отрезаем лишнее, т.к. поиск идет ровно до макимального возможного, т.е. до miner_pct/2
		pctArr = utils.DelUserPct(pctArr, userMaxKey)

		key = utils.GetMaxVote(pctArr, 0, userMaxKey, 100)
		newPct[currencyIdStr]["user_pct"] = utils.GetPctValue(key)
		newPctTpl[currencyIdStr]["user_pct"] = utils.Round((math.Pow(1+utils.StrToFloat64(utils.GetPctValue(key)), 3600*24*365)-1)*100, 2)
	}

	log.Debug("newPct", newPct)
	log.Debug("newPctTpl", newPctTpl)

	/*
	 * %/год
	 * */
	currencyPct := make(map[int64]map[string]string)
	for currencyId, name := range c.CurrencyList {
		pct, err := c.OneRow("SELECT * FROM pct WHERE currency_id  =  ? ORDER BY block_id DESC", currencyId).String()
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		currencyPct[currencyId] = make(map[string]string)
		currencyPct[currencyId]["name"] = name
		currencyPct[currencyId]["miner"] = utils.Float64ToStr(utils.Round((math.Pow(1+utils.StrToFloat64(pct["miner"]), 120)-1)*100, 6))
		currencyPct[currencyId]["user"] = utils.Float64ToStr(utils.Round((math.Pow(1+utils.StrToFloat64(pct["user"]), 120)-1)*100, 6))
	}

	TemplateStr, err := makeTemplate("statistic_voting", "statisticVoting", &StatisticVotingPage{
		Lang:                    c.Lang,
		CurrencyList:            c.CurrencyListCf,
		Js:                      template.JS(js),
		Divs:                    divs,
		CurrencyPct:             currencyPct,
		NewPctTpl:               newPctTpl,
		PctVotes:                pctVotes,
		VotesReferral:           votesReferral,
		VotesReduction:          votesReduction,
		PromisedAmount:          promisedAmount,
		NewMaxOtherCurrencies:   newMaxOtherCurrencies,
		MaxOtherCurrenciesVotes: maxOtherCurrenciesVotes,
		MaxPromisedAmountVotes:  maxPromisedAmountVotes,
		NewMaxPromisedAmounts:   newMaxPromisedAmounts,
		NewReferralPct:          newReferralPct,
		UserId:                  c.SessUserId})
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	return TemplateStr, nil
}
Пример #3
0
func (p *Parser) NewPctFront() error {

	err := p.generalCheck()
	if err != nil {
		return p.ErrInfo(err)
	}

	// является ли данный юзер майнером
	err = p.checkMiner(p.TxUserID)
	if err != nil {
		return p.ErrInfo(err)
	}

	nodePublicKey, err := p.GetNodePublicKey(p.TxUserID)
	if err != nil {
		return p.ErrInfo(err)
	}
	if len(nodePublicKey) == 0 {
		return p.ErrInfo("incorrect user_id")
	}

	newPctCurrency := make(map[string]map[string]string)
	// раньше не было рефских
	if p.BlockData != nil && p.BlockData.BlockId <= 77951 {
		err = json.Unmarshal([]byte(p.TxMap["new_pct"]), &newPctCurrency)
		if err != nil {
			return p.ErrInfo(err)
		}
	} else {
		newPctTx := new(newPctType)
		err = json.Unmarshal([]byte(p.TxMap["new_pct"]), &newPctTx)
		if err != nil {
			return p.ErrInfo(err)
		}
		if newPctTx.Referral == nil {
			return p.ErrInfo("!Referral")
		}
		newPctCurrency = newPctTx.Currency
	}
	if len(newPctCurrency) == 0 {
		return p.ErrInfo("!newPctCurrency")
	}

	// проверим, верно ли указаны ID валют
	currencyIdsSql := ""
	countCurrency := 0
	for id := range newPctCurrency {
		currencyIdsSql += id + ","
		countCurrency++
	}
	currencyIdsSql = currencyIdsSql[0 : len(currencyIdsSql)-1]
	count, err := p.Single("SELECT count(id) FROM currency WHERE id IN (" + currencyIdsSql + ")").Int()
	if err != nil {
		return p.ErrInfo(err)
	}
	if count != countCurrency {
		return p.ErrInfo("count_currency")
	}

	forSign := fmt.Sprintf("%s,%s,%s,%s", p.TxMap["type"], p.TxMap["time"], p.TxMap["user_id"], p.TxMap["new_pct"])
	CheckSignResult, err := utils.CheckSign([][]byte{nodePublicKey}, forSign, p.TxMap["sign"], true)
	if err != nil {
		return p.ErrInfo(err)
	}
	if !CheckSignResult {
		return p.ErrInfo("incorrect sign")
	}

	// проверим, прошло ли 2 недели с момента последнего обновления pct
	pctTime, err := p.Single("SELECT max(time) FROM pct").Int64()
	if err != nil {
		return p.ErrInfo(err)
	}
	if p.TxTime-pctTime <= p.Variables.Int64["new_pct_period"] {
		return p.ErrInfo(fmt.Sprintf("14 days error %d - %d <= %d", p.TxTime, pctTime, p.Variables.Int64["new_pct_period"]))
	}
	// берем все голоса miner_pct
	pctVotes := make(map[int64]map[string]map[string]int64)
	rows, err := p.Query("SELECT currency_id, pct, count(user_id) as votes FROM votes_miner_pct GROUP BY currency_id, pct ORDER BY currency_id, pct ASC")
	if err != nil {
		return p.ErrInfo(err)
	}
	defer rows.Close()
	for rows.Next() {
		var currency_id, votes int64
		var pct string
		err = rows.Scan(&currency_id, &pct, &votes)
		if err != nil {
			return p.ErrInfo(err)
		}
		log.Debug("newpctcurrency_id", currency_id, "pct", pct, "votes", votes)
		if len(pctVotes[currency_id]) == 0 {
			pctVotes[currency_id] = make(map[string]map[string]int64)
		}
		if len(pctVotes[currency_id]["miner_pct"]) == 0 {
			pctVotes[currency_id]["miner_pct"] = make(map[string]int64)
		}
		pctVotes[currency_id]["miner_pct"][pct] = votes
	}

	// берем все голоса user_pct
	rows, err = p.Query("SELECT currency_id, pct, count(user_id) as votes FROM votes_user_pct GROUP BY currency_id, pct ORDER BY currency_id, pct ASC")
	if err != nil {
		return p.ErrInfo(err)
	}
	defer rows.Close()
	for rows.Next() {
		var currency_id, votes int64
		var pct string
		err = rows.Scan(&currency_id, &pct, &votes)
		if err != nil {
			return p.ErrInfo(err)
		}
		log.Debug("currency_id", currency_id, "pct", pct, "votes", votes)
		if len(pctVotes[currency_id]) == 0 {
			pctVotes[currency_id] = make(map[string]map[string]int64)
		}
		if len(pctVotes[currency_id]["user_pct"]) == 0 {
			pctVotes[currency_id]["user_pct"] = make(map[string]int64)
		}
		pctVotes[currency_id]["user_pct"][pct] = votes
	}

	newPct := make(map[string]map[string]map[string]string)
	newPct["currency"] = make(map[string]map[string]string)
	var userMaxKey int64
	PctArray := utils.GetPctArray()

	log.Debug("pctVotes", pctVotes)
	for currencyId, data := range pctVotes {

		currencyIdStr := utils.Int64ToStr(currencyId)
		// определяем % для майнеров
		pctArr := utils.MakePctArray(data["miner_pct"])
		log.Debug("pctArrminer_pct", pctArr, currencyId)
		key := utils.GetMaxVote(pctArr, 0, 390, 100)
		log.Debug("key", key)
		if len(newPct["currency"][currencyIdStr]) == 0 {
			newPct["currency"][currencyIdStr] = make(map[string]string)
		}
		newPct["currency"][currencyIdStr]["miner_pct"] = utils.GetPctValue(key)

		// определяем % для юзеров
		pctArr = utils.MakePctArray(data["user_pct"])
		log.Debug("pctArruser_pct", pctArr, currencyId)
		// раньше не было завимости юзерского % от майнерского
		if p.BlockData != nil && p.BlockData.BlockId <= 95263 {
			userMaxKey = 390
		} else {
			log.Debug("newPct", newPct)
			pctY := utils.ArraySearch(newPct["currency"][currencyIdStr]["miner_pct"], PctArray)
			log.Debug("newPct[currency][currencyIdStr][miner_pct]", newPct["currency"][currencyIdStr]["miner_pct"])
			log.Debug("PctArray", PctArray)
			log.Debug("miner_pct $pct_y=", pctY)
			maxUserPctY := utils.Round(utils.StrToFloat64(pctY)/2, 2)
			userMaxKey = utils.FindUserPct(int(maxUserPctY))
			log.Debug("maxUserPctY", maxUserPctY, "userMaxKey", userMaxKey, "currencyIdStr", currencyIdStr)
			// отрезаем лишнее, т.к. поиск идет ровно до макимального возможного, т.е. до miner_pct/2
			pctArr = utils.DelUserPct(pctArr, userMaxKey)
			log.Debug("pctArr", pctArr)
		}
		key = utils.GetMaxVote(pctArr, 0, userMaxKey, 100)
		log.Debug("data[user_pct]", data["user_pct"])
		log.Debug("pctArr", pctArr)
		log.Debug("userMaxKey", userMaxKey)
		log.Debug("key", key)
		newPct["currency"][currencyIdStr]["user_pct"] = utils.GetPctValue(key)
		log.Debug("user_pct", newPct["currency"][currencyIdStr]["user_pct"])
	}

	var jsonData []byte
	// раньше не было рефских
	if p.BlockData != nil && p.BlockData.BlockId <= 77951 {

		newPct_ := newPct["currency"]
		jsonData, err = json.Marshal(newPct_)
		if err != nil {
			return p.ErrInfo(err)
		}
	} else {

		newPct_ := new(newPctType)
		newPct_.Currency = make(map[string]map[string]string)
		newPct_.Currency = newPct["currency"]
		newPct_.Referral = make(map[string]int64)
		refLevels := []string{"first", "second", "third"}
		for i := 0; i < len(refLevels); i++ {
			level := refLevels[i]
			var votesReferral []map[int64]int64

			// берем все голоса
			rows, err := p.Query("SELECT " + level + ", count(user_id) as votes FROM votes_referral GROUP BY " + level + " ORDER BY " + level + " ASC ")
			if err != nil {
				return p.ErrInfo(err)
			}
			defer rows.Close()
			for rows.Next() {
				var level_, votes int64
				err = rows.Scan(&level_, &votes)
				if err != nil {
					return p.ErrInfo(err)
				}
				votesReferral = append(votesReferral, map[int64]int64{level_: votes})
			}
			newPct_.Referral[level] = (utils.GetMaxVote(votesReferral, 0, 30, 10))
		}
		jsonData, err = json.Marshal(newPct_)
		if err != nil {
			return p.ErrInfo(err)
		}
	}

	if string(p.TxMap["new_pct"]) != string(jsonData) {
		return p.ErrInfo("p.TxMap[new_pct] != jsonData " + string(p.TxMap["new_pct"]) + "!=" + string(jsonData))
	}
	log.Debug(string(jsonData))

	return nil
}