Example #1
0
func (p *Parser) NewUserInit() error {
	err := p.GetTxMaps([]map[string]string{{"public_key": "bytes"}, {"sign": "bytes"}})
	if err != nil {
		return p.ErrInfo(err)
	}
	p.TxMap["public_key_hex"] = utils.BinToHex(p.TxMap["public_key"])
	p.TxMaps.Bytes["public_key_hex"] = utils.BinToHex(p.TxMaps.Bytes["public_key"])
	return nil
}
Example #2
0
func (p *Parser) MessageToAdminInit() error {
	fields := []map[string]string{{"encrypted_message": "bytes"}, {"sign": "bytes"}}
	err := p.GetTxMaps(fields)
	if err != nil {
		return p.ErrInfo(err)
	}
	p.TxMaps.Bytes["encrypted_message"] = utils.BinToHex(p.TxMaps.Bytes["encrypted_message"])
	p.TxMap["encrypted_message"] = utils.BinToHex(p.TxMap["encrypted_message"])
	return nil
}
Example #3
0
func (p *Parser) ChangeNodeKeyInit() error {

	fields := []map[string]string{{"new_node_public_key": "bytes"}, {"sign": "bytes"}}
	err := p.GetTxMaps(fields)
	if err != nil {
		return p.ErrInfo(err)
	}
	p.TxMaps.Bytes["new_node_public_key"] = utils.BinToHex(p.TxMaps.Bytes["new_node_public_key"])
	p.TxMap["new_node_public_key"] = utils.BinToHex(p.TxMap["new_node_public_key"])
	return nil
}
func (p *Parser) AdminChangePrimaryKeyInit() error {

	fields := []map[string]string{{"for_user_id": "int64"}, {"public_key": "bytes"}, {"sign": "bytes"}}
	err := p.GetTxMaps(fields)
	if err != nil {
		return p.ErrInfo(err)
	}
	p.TxMaps.Bytes["public_key_hex"] = utils.BinToHex(p.TxMaps.Bytes["public_key"])
	p.TxMap["public_key_hex"] = utils.BinToHex(p.TxMap["public_key"])
	return nil
}
Example #5
0
func (p *Parser) ChangePrimaryKeyRollback() error {

	// получим log_id, по которому можно найти данные, которые были до этого
	// $log_id всегда больше нуля, т.к. это откат обновления ключа
	logId, err := p.Single("SELECT log_id FROM users WHERE user_id  =  ?", p.TxUserID).Int64()
	if err != nil {
		return p.ErrInfo(err)
	}

	// данные, которые восстановим
	var public_key_0, public_key_1, public_key_2 []byte
	var prev_log_id int64
	err = p.QueryRow(p.FormatQuery("SELECT public_key_0, public_key_1, public_key_2, prev_log_id FROM log_users WHERE log_id  =  ?"), logId).Scan(&public_key_0, &public_key_1, &public_key_2, &prev_log_id)
	if err != nil && err != sql.ErrNoRows {
		return p.ErrInfo(err)
	}
	if len(public_key_0) > 0 {
		public_key_0 = utils.BinToHex(public_key_0)
	}
	if len(public_key_1) > 0 {
		public_key_1 = utils.BinToHex(public_key_1)
	}
	if len(public_key_2) > 0 {
		public_key_2 = utils.BinToHex(public_key_2)
	}

	err = p.ExecSql("UPDATE users SET public_key_0 = [hex], public_key_1 = [hex], public_key_2 = [hex], log_id = ? WHERE user_id = ?", public_key_0, public_key_1, public_key_2, prev_log_id, p.TxUserID)
	if err != nil {
		return p.ErrInfo(err)
	}
	// подчищаем _log
	err = p.ExecSql("DELETE FROM log_users WHERE log_id = ?", logId)
	if err != nil {
		return p.ErrInfo(err)
	}
	p.rollbackAI("log_users", 1)

	// проверим, не наш ли это user_id
	myUserId, _, myPrefix, _, err := p.GetMyUserId(p.TxUserID)
	if err != nil {
		return err
	}
	if p.TxUserID == myUserId {
		// обновим статус в нашей локальной табле.
		err = p.ExecSql("UPDATE "+myPrefix+"my_keys SET status = 'my_pending', block_id = 0, time = 0 WHERE hex(public_key) = ? AND status = 'approved' AND block_id = ?", p.newPublicKeysHex[0], p.BlockData.BlockId)
		if err != nil {
			return p.ErrInfo(err)
		}
	}

	return nil
}
Example #6
0
func (p *Parser) NewMinerInit() error {
	var fields []map[string]string
	if p.BlockData != nil && p.BlockData.BlockId < 250900 {
		fields = []map[string]string{{"race": "int64"}, {"country": "int64"}, {"latitude": "float64"}, {"longitude": "float64"}, {"http_host": "string"}, {"face_coords": "string"}, {"profile_coords": "string"}, {"face_hash": "string"}, {"profile_hash": "string"}, {"video_type": "string"}, {"video_url_id": "string"}, {"node_public_key": "bytes"}, {"sign": "bytes"}}
	} else {
		fields = []map[string]string{{"race": "int64"}, {"country": "int64"}, {"latitude": "float64"}, {"longitude": "float64"}, {"http_host": "string"}, {"tcp_host": "string"}, {"face_coords": "string"}, {"profile_coords": "string"}, {"face_hash": "string"}, {"profile_hash": "string"}, {"video_type": "string"}, {"video_url_id": "string"}, {"node_public_key": "bytes"}, {"sign": "bytes"}}
	}
	err := p.GetTxMaps(fields)
	if err != nil {
		return p.ErrInfo(err)
	}
	p.TxMap["node_public_key"] = utils.BinToHex(p.TxMap["node_public_key"])
	p.TxMaps.Bytes["node_public_key"] = utils.BinToHex(p.TxMaps.Bytes["node_public_key"])
	return nil
}
Example #7
0
/* не забываем, что cash_request_OUT_front проверяет формат amount,
 * можно ли делать запрос указанному юзеру, есть ли у юзера
 * обещанные суммы на сумму amount, есть ли нужное кол-во DC у отправителя,
 * является ли отправитель майнером
 *
 * */
func (p *Parser) CashRequestInFront() error {

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

	// code может быть чем угодно, т.к. отправитель шлет в сеть лишь хэш
	// нигде, кроме cash_request_in_front, code не используется
	// if ( !check_input_data ($this->tx_data['code'], 'cash_code') )
	//	return 'cash_request_in_front code';

	verifyData := map[string]string{"cash_request_id": "bigint"}
	err = p.CheckInputData(verifyData)
	if err != nil {
		return p.ErrInfo(err)
	}

	var to_user_id, cTime int64
	var status string
	var hash_code []byte
	err = p.QueryRow(p.FormatQuery("SELECT to_user_id, status, hash_code, time FROM cash_requests WHERE id  =  ?"), p.TxMaps.Int64["cash_request_id"]).Scan(&to_user_id, &status, &hash_code, &cTime)
	if err != nil && err != sql.ErrNoRows {
		return p.ErrInfo(err)
	}

	// ID cash_requests юзер указал сам, значит это может быть случайное число.
	// проверим, является получателем наш юзер
	if to_user_id != p.TxUserID {
		return p.ErrInfo("to_user_id!=user_id")
	}
	// должно быть pending
	if status != "pending" {
		return p.ErrInfo("status!=pending")
	}
	// проверим код
	if !bytes.Equal(utils.DSha256(p.TxMaps.String["code"]), utils.BinToHex(hash_code)) {
		return p.ErrInfo("code!=hash_code")
	}
	var txTime int64
	if p.BlockData != nil { // тр-ия пришла в блоке
		txTime = p.BlockData.Time
	} else {
		txTime = time.Now().Unix() // просто на всякий случай небольшой запас
	}
	// запрос может быть принят, только если он был отправлен не позднее чем через cash_request_time сек назад
	if cTime < txTime-p.Variables.Int64["cash_request_time"] {
		return p.ErrInfo(fmt.Sprintf("%d < %d - %d", cTime, txTime, p.Variables.Int64["cash_request_time"]))
	}

	forSign := fmt.Sprintf("%s,%s,%s,%s,%s", p.TxMap["type"], p.TxMap["time"], p.TxMap["user_id"], p.TxMap["cash_request_id"], p.TxMap["code"])
	CheckSignResult, err := utils.CheckSign(p.PublicKeys, forSign, p.TxMap["sign"], false)
	if err != nil {
		return p.ErrInfo(err)
	}
	if !CheckSignResult {
		return p.ErrInfo("incorrect sign")
	}
	return nil
}
Example #8
0
func (c *Controller) EncryptChatMessage() (string, error) {

	var err error

	c.r.ParseForm()

	receiver := c.r.FormValue("receiver")
	message := c.r.FormValue("message")
	if len(message) > 5120 {
		return "", errors.New("incorrect message")
	}

	publicKey, err := c.Single("SELECT public_key_0 FROM users WHERE user_id  =  ?", receiver).Bytes()
	if err != nil {
		return "", utils.ErrInfo(err)
	}

	if len(publicKey) > 0 {
		pub, err := utils.BinToRsaPubKey(publicKey)
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		enc_, err := rsa.EncryptPKCS1v15(rand.Reader, pub, []byte(message))
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		return utils.JsonAnswer(string(utils.BinToHex(enc_)), "success").String(), nil
	} else {
		return utils.JsonAnswer("Incorrect user_id", "error").String(), nil
	}

}
Example #9
0
func (p *Parser) ChangeNodeKey() error {

	// Всегда есть, что логировать, т.к. это обновление ключа
	logData, err := p.OneRow("SELECT * FROM miners_data WHERE user_id  =  ?", p.TxUserID).String()
	if err != nil {
		return p.ErrInfo(err)
	}
	nodePublicKeyHex := utils.BinToHex([]byte(logData["node_public_key"]))

	logId, err := p.ExecSqlGetLastInsertId("INSERT INTO log_miners_data ( node_public_key, block_id, prev_log_id ) VALUES ( [hex], ?, ? )", "log_id", nodePublicKeyHex, p.BlockData.BlockId, logData["log_id"])
	if err != nil {
		return p.ErrInfo(err)
	}
	err = p.ExecSql("UPDATE miners_data SET node_public_key = [hex], log_id = ? WHERE user_id = ?", p.TxMaps.Bytes["new_node_public_key"], logId, p.TxUserID)
	if err != nil {
		return p.ErrInfo(err)
	}

	// проверим, не наш ли это user_id
	myUserId, myBlockId, myPrefix, _, err := p.GetMyUserId(p.TxMaps.Int64["user_id"])
	if err != nil {
		return err
	}
	if p.TxUserID == myUserId && myBlockId <= p.BlockData.BlockId {
		// обновим статус в нашей локальной табле.
		err = p.ExecSql("UPDATE "+myPrefix+"my_node_keys SET status = 'approved', block_id = ?, time = ? WHERE hex(public_key) = ? AND status = 'my_pending'", p.BlockData.BlockId, p.BlockData.Time, p.TxMaps.Bytes["new_node_public_key"])
		if err != nil {
			return p.ErrInfo(err)
		}
	}

	return nil
}
Example #10
0
func (p *Parser) MoneyBackRequestFront() error {

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

	verifyData := map[string]string{"order_id": "bigint", "seller_enc_text": "comment", "arbitrator0_enc_text": "comment", "arbitrator1_enc_text": "comment", "arbitrator2_enc_text": "comment", "arbitrator3_enc_text": "comment", "arbitrator4_enc_text": "comment"}
	err = p.CheckInputData(verifyData)
	if err != nil {
		return p.ErrInfo(err)
	}

	var txTime int64
	if p.BlockData != nil { // тр-ия пришла в блоке
		txTime = p.BlockData.Time
	} else { // голая тр-ия
		txTime = time.Now().Unix() - 30 // просто на всякий случай небольшой запас
	}

	// проверим, есть ли такой ордер, не был ли ранее запрос, точно ли покупатель наш юзер
	orderId, err := p.Single("SELECT id FROM orders WHERE id  =  ? AND status  =  'normal' AND end_time > ? AND buyer  =  ?", p.TxMaps.Int64["order_id"], txTime, p.TxUserID).Int64()
	if err != nil {
		return p.ErrInfo(err)
	}
	if orderId == 0 {
		return p.ErrInfo("orderId==0")
	}

	forSign := ""
	if p.BlockData != nil && p.BlockData.BlockId < 197115 {
		forSign = fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", p.TxMap["type"], p.TxMap["time"], p.TxMap["user_id"], p.TxMap["order_id"], p.TxMap["arbitrator0_enc_text"], p.TxMap["arbitrator1_enc_text"], p.TxMap["arbitrator2_enc_text"], p.TxMap["arbitrator3_enc_text"], p.TxMap["arbitrator4_enc_text"], p.TxMap["seller_enc_text"])

	} else {
		encData := make(map[string]string)
		for i := 0; i < 5; i++ {
			iStr := utils.IntToStr(i)
			encData["arbitrator"+iStr+"_enc_text"] = string(utils.BinToHex(p.TxMap["arbitrator"+iStr+"_enc_text"]))
			if encData["arbitrator"+iStr+"_enc_text"] == "00" {
				encData["arbitrator"+iStr+"_enc_text"] = "0"
			}
		}
		forSign = fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", p.TxMap["type"], p.TxMap["time"], p.TxMap["user_id"], p.TxMap["order_id"], encData["arbitrator0_enc_text"], encData["arbitrator1_enc_text"], encData["arbitrator2_enc_text"], encData["arbitrator3_enc_text"], encData["arbitrator4_enc_text"], utils.BinToHex(p.TxMap["seller_enc_text"]))
	}

	CheckSignResult, err := utils.CheckSign(p.PublicKeys, forSign, p.TxMap["sign"], false)
	if err != nil {
		return p.ErrInfo(err)
	}
	if !CheckSignResult {
		return p.ErrInfo("incorrect sign")
	}

	err = p.limitRequest(consts.LIMIT_MONEY_BACK_REQUEST, "money_back_request", consts.LIMIT_MONEY_BACK_REQUEST_PERIOD)
	if err != nil {
		return p.ErrInfo(err)
	}
	return nil
}
Example #11
0
func (p *Parser) ChangeKeyActiveInit() error {

	fields := []map[string]string{{"secret": "bytes"}, {"sign": "bytes"}}
	err := p.GetTxMaps(fields)
	if err != nil {
		return p.ErrInfo(err)
	}
	p.TxMaps.String["secret_hex"] = string(utils.BinToHex(p.TxMaps.Bytes["secret"]))
	if p.TxMaps.String["secret_hex"] == "30" {
		p.TxMaps.Int64["active"] = 0
	} else {
		p.TxMaps.Int64["active"] = 1
	}
	p.TxMaps.String["secret_hex"] = string(utils.BinToHex(p.TxMaps.Bytes["secret"]))

	return nil
}
Example #12
0
func (p *Parser) SendDcInit() error {
	var fields []map[string]string
	if p.BlockData != nil && p.BlockData.BlockId <= consts.ARBITRATION_BLOCK_START {
		fields = []map[string]string{{"to_user_id": "int64"}, {"currency_id": "int64"}, {"amount": "float64"}, {"commission": "float64"}, {"comment": "string"}, {"sign": "bytes"}}
	} else {
		fields = []map[string]string{{"to_user_id": "int64"}, {"currency_id": "int64"}, {"amount": "float64"}, {"commission": "float64"}, {"arbitrator0": "int64"}, {"arbitrator1": "int64"}, {"arbitrator2": "int64"}, {"arbitrator3": "int64"}, {"arbitrator4": "int64"}, {"arbitrator0_commission": "float64"}, {"arbitrator1_commission": "float64"}, {"arbitrator2_commission": "float64"}, {"arbitrator3_commission": "float64"}, {"arbitrator4_commission": "float64"}, {"comment": "string"}, {"sign": "bytes"}}
	}

	err := p.GetTxMaps(fields)
	if err != nil {
		return p.ErrInfo(err)
	}
	p.TxMaps.Bytes["hash_hex"] = utils.BinToHex(p.TxMaps.Bytes["hash"])
	p.TxMaps.Int64["from_user_id"] = p.TxMaps.Int64["user_id"]
	p.TxMap["hash_hex"] = utils.BinToHex(p.TxMap["hash"])
	p.TxMap["from_user_id"] = p.TxMap["user_id"]
	if p.TxMaps.String["comment"] == "null" {
		p.TxMaps.String["comment"] = ""
		p.TxMap["comment"] = []byte("")
	}
	return nil
}
Example #13
0
func (c *Controller) CheckSetupPassword() (string, error) {

	c.r.ParseForm()
	password, err := c.Single(`SELECT setup_password FROM config WHERE setup_password = ?`, utils.DSha256(c.r.FormValue("password"))).String()
	if err != nil {
		return "", err
	}
	if len(password) > 0 && !c.Community {
		userId, err := c.GetMyUserId("")
		if err != nil {
			return "", err
		}
		publicKey, err := c.GetUserPublicKey(userId)
		if err != nil {
			return "", err
		}
		c.sess.Set("user_id", userId)
		c.sess.Set("public_key", string(utils.BinToHex(publicKey)))
		log.Debug("public_key check: %s", string(utils.BinToHex(publicKey)))
		return "ok", nil
	}
	return "", nil

}
Example #14
0
func (c *Controller) EDataBaseDump() (string, error) {

	if !c.NodeAdmin || c.SessRestricted != 0 {
		return "", utils.ErrInfo(errors.New("Permission denied"))
	}

	allTables, err := c.GetAllTables()
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	c.r.ParseForm()

	mainMap := make(map[string][]map[string]string)

	for _, table := range allTables {
		re := regexp.MustCompile("^e_")
		match := re.FindStringSubmatch(table)
		if len(match) > 0 {
			data, err := c.GetAll(`SELECT * FROM `+table, -1)
			if err != nil {
				return "", utils.ErrInfo(err)
			}
			for k, arr := range data {
				for name, value := range arr {
					if ok, _ := regexp.MatchString("(tx_hash)", name); ok {
						data[k][name] = string(utils.BinToHex([]byte(value)))
					}
				}
			}
			mainMap[table] = data
		}
	}

	jsonData, _ := json.Marshal(mainMap)
	log.Debug(string(jsonData))

	c.w.Header().Set("Content-Type", "text/plain")
	c.w.Header().Set("Content-Length", utils.IntToStr(len(jsonData)))
	t := time.Unix(utils.Time(), 0)
	c.w.Header().Set("Content-Disposition", `attachment; filename="dcoin_e_backup-`+t.Format(c.TimeFormat)+`.txt`)
	if _, err := c.w.Write(jsonData); err != nil {
		return "", utils.ErrInfo(errors.New("unable to write text"))
	}

	return "", nil
}
Example #15
0
func (p *Parser) ChangeNodeKeyRollback() error {
	// получим log_id, по которому можно найти данные, которые были до этого
	// $log_id всегда больше нуля, т.к. это откат обновления ключа

	logId, err := p.Single("SELECT log_id FROM miners_data WHERE user_id  =  ?", p.TxUserID).Int64()
	if err != nil {
		return p.ErrInfo(err)
	}

	// данные, которые восстановим
	data, err := p.OneRow("SELECT node_public_key, prev_log_id FROM log_miners_data WHERE log_id  =  ?", logId).String()
	if err != nil {
		return p.ErrInfo(err)
	}
	nodePublicKeyHex := utils.BinToHex([]byte(data["node_public_key"]))
	err = p.ExecSql("UPDATE miners_data SET node_public_key =[hex], log_id = ? WHERE user_id = ?", nodePublicKeyHex, data["prev_log_id"], p.TxUserID)
	if err != nil {
		return p.ErrInfo(err)
	}

	// подчищаем _log
	err = p.ExecSql("DELETE FROM log_miners_data WHERE log_id = ?", logId)
	if err != nil {
		return p.ErrInfo(err)
	}
	err = p.rollbackAI("log_miners_data", 1)
	if err != nil {
		return p.ErrInfo(err)
	}
	// проверим, не наш ли это user_id
	myUserId, _, myPrefix, _, err := p.GetMyUserId(p.TxMaps.Int64["user_id"])
	if err != nil {
		return err
	}
	if p.TxUserID == myUserId {
		// обновим статус в нашей локальной табле.
		err = p.ExecSql("UPDATE "+myPrefix+"my_node_keys SET status = 'my_pending', block_id = 0, time = 0 WHERE hex(public_key) = ? AND status = 'approved' AND block_id = ?", p.TxMaps.Bytes["new_node_public_key"], p.BlockData.BlockId)
		if err != nil {
			return p.ErrInfo(err)
		}
	}

	return nil
}
Example #16
0
func (c *Controller) PoolAdminLogin() (string, error) {

	if !c.PoolAdmin {
		return "", utils.ErrInfo(errors.New("access denied"))
	}

	c.r.ParseForm()
	userId := int64(utils.StrToFloat64(c.Parameters["userId"]))
	publicKey, err := c.GetUserPublicKey(userId)
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	c.sess.Set("user_id", userId)
	c.sess.Set("public_key", string(utils.BinToHex(publicKey)))

	TemplateStr, err := makeTemplate("pool_admin_login", "poolAdminLogin", &poolAdminPage{})
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	return TemplateStr, nil
}
Example #17
0
func (p *Parser) ChangePrimaryKeyInit() error {
	var err error
	fields := []string{"bin_public_keys", "sign"}
	p.TxMap, err = p.GetTxMap(fields)
	if err != nil {
		return p.ErrInfo(err)
	}

	// в 1 new_public_keys может быть от 1 до 3-х ключей
	i := 0
	bin_public_keys := p.TxMap["bin_public_keys"]
	for {
		length := utils.DecodeLength(&bin_public_keys)
		pKey := utils.BytesShift(&bin_public_keys, length)
		p.newPublicKeysHex[i] = utils.BinToHex(pKey)
		if len(bin_public_keys) == 0 || i > 1 {
			break
		}
		i++
	}
	return nil
}
Example #18
0
func (p *Parser) SendDcFront() error {

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

	verifyData := map[string]string{"from_user_id": "bigint", "to_user_id": "bigint", "currency_id": "bigint", "amount": "amount", "commission": "amount", "comment": "comment"}
	err = p.CheckInputData(verifyData)
	if err != nil {
		return p.ErrInfo(err)
	}

	if p.TxMaps.Float64["amount"] < 0.01 { // 0.01 - минимальная сумма
		return p.ErrInfo("amount")
	}

	// проверим, существует ли такая валюта в таблиуе DC-валют
	checkCurrency, err := p.CheckCurrency(p.TxMaps.Int64["currency_id"])
	if !checkCurrency {
		// если нет, то проверяем список CF-валют
		checkCurrency, err := p.CheckCurrencyCF(p.TxMaps.Int64["currency_id"])
		if err != nil {
			return p.ErrInfo(err)
		}
		if !checkCurrency {
			return p.ErrInfo("currency_id")
		}
	}

	nodeCommission, err := p.getMyNodeCommission(p.TxMaps.Int64["currency_id"], p.TxUserID, p.TxMaps.Float64["amount"])
	if err != nil {
		return p.ErrInfo(err)
	}

	// проверим, удовлетворяет ли нас комиссия, которую предлагает юзер
	if p.TxMaps.Float64["commission"] < nodeCommission {
		return p.ErrInfo(fmt.Sprintf("commission %v<%v", p.TxMaps.Float64["commission"], nodeCommission))
	}

	if p.BlockData != nil && p.BlockData.BlockId <= consts.ARBITRATION_BLOCK_START {
		for i := 0; i < 5; i++ {
			p.TxMaps.Float64["arbitrator"+utils.IntToStr(i)+"_commission"] = 0 // для check_sender_money
		}
		forSign := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", p.TxMap["type"], p.TxMap["time"], p.TxMap["user_id"], p.TxMap["to_user_id"], p.TxMap["amount"], p.TxMap["commission"], utils.BinToHex(p.TxMap["comment"]), p.TxMap["currency_id"])
		CheckSignResult, err := utils.CheckSign(p.PublicKeys, forSign, p.TxMap["sign"], false)
		if err != nil {
			return p.ErrInfo(err)
		}
		if !CheckSignResult {
			return p.ErrInfo("incorrect sign")
		}
	} else {
		dupArray := make(map[int64]int64)
		for i := 0; i < 5; i++ {
			arbitrator__commission := "arbitrator" + utils.IntToStr(i) + "_commission"
			arbitrator_ := "arbitrator" + utils.IntToStr(i)
			if !utils.CheckInputData(p.TxMap[arbitrator__commission], "amount") {
				return p.ErrInfo("arbitrator_commission")
			}
			if !utils.CheckInputData(p.TxMap[arbitrator_], "bigint") {
				return p.ErrInfo("arbitrator")
			}
			// если указал ID арбитра, то должна быть комиссия для него
			if p.TxMaps.Int64[arbitrator_] > 0 && p.TxMaps.Float64[arbitrator__commission] < 0.01 {
				return p.ErrInfo("arbitrator_commission")
			}

			// на всяк случай не даем арбитрам возможность быть арбитрами самим себе
			if p.TxMaps.Int64[arbitrator_] == p.TxUserID {
				return p.ErrInfo("arbitrator = user_id")
			}

			if p.TxMaps.Int64[arbitrator_] > 0 {
				dupArray[utils.BytesToInt64(p.TxMap[arbitrator_])]++
				if dupArray[utils.BytesToInt64(p.TxMap[arbitrator_])] > 1 {
					return p.ErrInfo("doubles")
				}
			}
			if p.TxMaps.Int64[arbitrator_] > 0 {

				arbitrator := p.TxMap[arbitrator_]
				// проверим, является ли арбитром указанный user_id
				arbitratorConditionsJson, err := p.Single("SELECT conditions FROM arbitrator_conditions WHERE user_id  =  ?", utils.BytesToInt64(arbitrator)).Bytes()
				if err != nil {
					return p.ErrInfo(err)
				}
				arbitratorConditionsMap := make(map[string][5]string)
				err = json.Unmarshal(arbitratorConditionsJson, &arbitratorConditionsMap)
				// арбитр к этому моменту мог передумать и убрать свои условия, уйдя из арбитров для новых сделок поставив [0] что вызовет тут ошибку
				if err != nil {
					log.Debug("arbitratorConditionsJson", arbitratorConditionsJson)
					return p.ErrInfo(err)
				}
				// проверим, работает ли выбранный арбитр с валютой данной сделки
				var checkCurrency int64
				if p.TxMaps.Int64["currency_id"] > 1000 {
					checkCurrency = 1000
				} else {
					checkCurrency = p.TxMaps.Int64["currency_id"]
				}
				if len(arbitratorConditionsMap[utils.Int64ToStr(checkCurrency)]) == 0 {
					return p.ErrInfo("len(arbitratorConditionsMap[checkCurrency]) == 0")
				}
				// указан ли этот арбитр в списке доверенных у продавца
				sellerArbitrator, err := p.Single("SELECT user_id FROM arbitration_trust_list WHERE user_id  =  ? AND arbitrator_user_id  =  ?", p.TxMaps.Int64["to_user_id"], utils.BytesToInt64(arbitrator)).Int64()
				if err != nil {
					return p.ErrInfo(err)
				}
				if sellerArbitrator == 0 {
					return p.ErrInfo("sellerArbitrator == 0")
				}
				// указан ли этот арбитр в списке доверенных у покупателя
				buyerArbitrator, err := p.Single("SELECT user_id FROM arbitration_trust_list WHERE user_id  =  ? AND arbitrator_user_id  =  ?", p.TxMaps.Int64["from_user_id"], utils.BytesToInt64(arbitrator)).Int64()
				if err != nil {
					return p.ErrInfo(err)
				}
				if buyerArbitrator == 0 {
					return p.ErrInfo("buyerArbitrator == 0")
				}
				// согласен ли продавец на манибек
				arbitrationDaysRefund, err := p.Single("SELECT arbitration_days_refund FROM users WHERE user_id  =  ?", p.TxMaps.Int64["to_user_id"]).Int64()
				if err != nil {
					return p.ErrInfo(err)
				}
				if arbitrationDaysRefund == 0 {
					return p.ErrInfo("buyerArbitrator == 0")
				}
				// готов ли арбитр рассматривать такую сумму сделки
				currencyIdStr := utils.Int64ToStr(p.TxMaps.Int64["currency_id"])
				if p.TxMaps.Float64["amount"] < utils.StrToFloat64(arbitratorConditionsMap[currencyIdStr][0]) ||
					(p.TxMaps.Float64["amount"] > utils.StrToFloat64(arbitratorConditionsMap[currencyIdStr][1]) && utils.StrToFloat64(arbitratorConditionsMap[currencyIdStr][1]) > 0) {
					return p.ErrInfo("amount")
				}
				// мин. комиссия, на которую согласен арбитр
				minArbitratorCommission := utils.StrToFloat64(arbitratorConditionsMap[currencyIdStr][4]) / 100 * p.TxMaps.Float64["amount"]
				if minArbitratorCommission > utils.StrToFloat64(arbitratorConditionsMap[currencyIdStr][3]) && utils.StrToFloat64(arbitratorConditionsMap[currencyIdStr][3]) > 0 {
					minArbitratorCommission = utils.StrToFloat64(arbitratorConditionsMap[currencyIdStr][3])
				}
				if minArbitratorCommission < utils.StrToFloat64(arbitratorConditionsMap[currencyIdStr][2]) {
					minArbitratorCommission = utils.StrToFloat64(arbitratorConditionsMap[currencyIdStr][2])
				}
				if utils.BytesToFloat64(p.TxMap[arbitrator__commission]) < minArbitratorCommission {
					return p.ErrInfo(" < minArbitratorCommission")
				}
			}
		}

		forSign := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", p.TxMap["type"], p.TxMap["time"], p.TxMap["user_id"], p.TxMap["to_user_id"], p.TxMap["amount"], p.TxMap["commission"], p.TxMap["arbitrator0"], p.TxMap["arbitrator1"], p.TxMap["arbitrator2"], p.TxMap["arbitrator3"], p.TxMap["arbitrator4"], p.TxMap["arbitrator0_commission"], p.TxMap["arbitrator1_commission"], p.TxMap["arbitrator2_commission"], p.TxMap["arbitrator3_commission"], p.TxMap["arbitrator4_commission"], utils.BinToHex(p.TxMap["comment"]), p.TxMap["currency_id"])
		CheckSignResult, err := utils.CheckSign(p.PublicKeys, forSign, p.TxMap["sign"], false)
		if err != nil {
			return p.ErrInfo(err)
		}
		if !CheckSignResult {
			return p.ErrInfo("incorrect sign")
		}
	}

	/*
			wallets_buffer сделан не для защиты от двойной траты, а для того, чтобы нода, которая генерит блок не записала
			двойное списание в свой блок, который будет отправлен другим нодам и будет ими отвергнут.
		   Для тр-ий типа new_forex_order используется простой запрет на запись в блок тр-ии new_forex_order+new_forex_order или
		   new_forex_order+send_dc и пр.
		   защита от двойного списания на основе даннных из блока, полученного из сети заключается в постепенной обработке
		   тр-ий путем проверки front_ и занесения данных в БД (ParseDataFull).
	*/
	amountAndCommission, err := p.checkSenderMoney(p.TxMaps.Int64["currency_id"], p.TxMaps.Int64["from_user_id"], p.TxMaps.Float64["amount"], p.TxMaps.Float64["commission"], p.TxMaps.Float64["arbitrator0_commission"], p.TxMaps.Float64["arbitrator1_commission"], p.TxMaps.Float64["arbitrator2_commission"], p.TxMaps.Float64["arbitrator3_commission"], p.TxMaps.Float64["arbitrator4_commission"])
	if err != nil {
		return p.ErrInfo(err)
	}

	// существует ли юзер-получатель
	err = p.CheckUser(p.TxMaps.Int64["to_user_id"])
	if err != nil {
		return p.ErrInfo(err)
	}

	err = p.checkSpamMoney(p.TxMaps.Int64["currency_id"], p.TxMaps.Float64["amount"])
	if err != nil {
		return p.ErrInfo(err)
	}

	// вычитаем из wallets_buffer
	// amount_and_commission взято из check_sender_money()
	err = p.updateWalletsBuffer(amountAndCommission, p.TxMaps.Int64["currency_id"])
	if err != nil {
		return p.ErrInfo(err)
	}

	return nil
}
Example #19
0
func (p *Parser) SendDc() error {
	// нужно отметить в log_time_money_orders, что тр-ия прошла в блок
	err := p.ExecSql("UPDATE log_time_money_orders SET del_block_id = ? WHERE hex(tx_hash) = ?", p.BlockData.BlockId, p.TxHash)
	if err != nil {
		return p.ErrInfo(err)
	}

	// 1 возможно нужно обновить таблицу points_status
	err = p.pointsUpdateMain(p.BlockData.UserId)
	if err != nil {
		return p.ErrInfo(err)
	}
	// 2
	err = p.pointsUpdateMain(p.TxMaps.Int64["from_user_id"])
	if err != nil {
		return p.ErrInfo(err)
	}
	// 3
	err = p.pointsUpdateMain(p.TxMaps.Int64["to_user_id"])
	if err != nil {
		return p.ErrInfo(err)
	}
	commission := p.TxMaps.Float64["commission"]

	var arbitration_days_refund int64
	var seller_hold_back_pct float64
	var arbitrators bool
	if p.BlockData.BlockId > consts.ARBITRATION_BLOCK_START {
		// на какой период манибека согласен продавец
		err := p.QueryRow(p.FormatQuery("SELECT arbitration_days_refund, seller_hold_back_pct FROM users WHERE user_id  =  ?"), p.TxMaps.Int64["to_user_id"]).Scan(&arbitration_days_refund, &seller_hold_back_pct)
		if err != nil && err != sql.ErrNoRows {
			return p.ErrInfo(err)
		}
		if arbitration_days_refund > 0 {
			for i := 0; i < 5; i++ {
				iStr := utils.IntToStr(i)
				if p.TxMaps.Int64["arbitrator"+iStr] > 0 && p.TxMaps.Float64["arbitrator"+iStr+"_commission"] >= 0.01 {
					// нужно учесть комиссию арбитра
					commission += p.TxMaps.Float64["arbitrator"+iStr+"_commission"]
					arbitrators = true
				}
			}
		}
	}
	// 4 обновим сумму на кошельке отправителя, залогировав предыдущее значение
	err = p.updateSenderWallet(p.TxMaps.Int64["from_user_id"], p.TxMaps.Int64["currency_id"], p.TxMaps.Float64["amount"], commission, "from_user", p.TxMaps.Int64["to_user_id"], p.TxMaps.Int64["to_user_id"], string(utils.BinToHex(p.TxMap["comment"])), "encrypted")
	if err != nil {
		return p.ErrInfo(err)
	}

	log.Debug("SendDC updateRecipientWallet")
	// 5 обновим сумму на кошельке получателю
	err = p.updateRecipientWallet(p.TxMaps.Int64["to_user_id"], p.TxMaps.Int64["currency_id"], p.TxMaps.Float64["amount"], "from_user", p.TxMaps.Int64["from_user_id"], p.TxMaps.String["comment"], "encrypted", true)
	if err != nil {
		return p.ErrInfo(err)
	}

	// 6 теперь начисляем комиссию майнеру, который этот блок сгенерил
	if p.TxMaps.Float64["commission"] >= 0.01 {
		err = p.updateRecipientWallet(p.BlockData.UserId, p.TxMaps.Int64["currency_id"], p.TxMaps.Float64["commission"], "node_commission", p.BlockData.BlockId, "", "encrypted", true)
		if err != nil {
			return p.ErrInfo(err)
		}
	}

	log.Debug("p.BlockData.BlockId", p.BlockData.BlockId)
	log.Debug("consts.ARBITRATION_BLOCK_START", consts.ARBITRATION_BLOCK_START)
	if p.BlockData.BlockId > consts.ARBITRATION_BLOCK_START {

		// если продавец не согласен на арбитраж, то $arbitration_days_refund будет равно 0

		log.Debug("arbitration_days_refund", arbitration_days_refund)
		log.Debug("arbitrators", arbitrators)
		if arbitration_days_refund > 0 && arbitrators {
			holdBackAmount := math.Floor(utils.Round(p.TxMaps.Float64["amount"]*(seller_hold_back_pct/100), 3)*100) / 100
			if holdBackAmount < 0.01 {
				holdBackAmount = 0.01
			}
			orderId, err := p.ExecSqlGetLastInsertId("INSERT INTO orders ( time, buyer, seller, arbitrator0, arbitrator1, arbitrator2, arbitrator3, arbitrator4, amount, hold_back_amount, currency_id, block_id, end_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )", "id", p.BlockData.Time, p.TxMaps.Int64["from_user_id"], p.TxMaps.Int64["to_user_id"], p.TxMaps.Int64["arbitrator0"], p.TxMaps.Int64["arbitrator1"], p.TxMaps.Int64["arbitrator2"], p.TxMaps.Int64["arbitrator3"], p.TxMaps.Int64["arbitrator4"], p.TxMaps.Float64["amount"], holdBackAmount, p.TxMaps.Int64["currency_id"], p.BlockData.BlockId, (p.BlockData.Time + arbitration_days_refund*86400))
			if err != nil {
				return p.ErrInfo(err)
			}
			// начисляем комиссию арбитрам
			for i := 0; i < 5; i++ {
				iStr := utils.IntToStr(i)
				log.Debug("arbitrator_commission "+iStr, p.TxMaps.Float64["arbitrator"+iStr+"_commission"])
				if p.TxMaps.Int64["arbitrator"+iStr] > 0 && p.TxMaps.Float64["arbitrator"+iStr+"_commission"] >= 0.01 {
					log.Debug("updateRecipientWallet")
					err = p.updateRecipientWallet(p.TxMaps.Int64["arbitrator"+iStr], p.TxMaps.Int64["currency_id"], p.TxMaps.Float64["arbitrator"+iStr+"_commission"], "arbitrator_commission", orderId, "", "encrypted", true)
					if err != nil {
						return p.ErrInfo(err)
					}
				}
			}
		}
	}
	// отмечаем данную транзакцию в буфере как отработанную и ставим в очередь на удаление
	err = p.ExecSql("UPDATE wallets_buffer SET del_block_id = ? WHERE hex(hash) = ?", p.BlockData.BlockId, p.TxHash)
	if err != nil {
		return p.ErrInfo(err)
	}

	return nil
}
Example #20
0
func Exchange(chBreaker chan bool, chAnswer chan string) {

	defer func() {
		if r := recover(); r != nil {
			log.Error("daemon Recovered", r)
			panic(r)
		}
	}()

	const GoroutineName = "Exchange"
	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
	}

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

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

		blockId, err := d.GetConfirmedBlockId()
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}

		var myPrefix string
		community, err := d.GetCommunityUsers()
		if len(community) > 0 {
			adminUserId, err := d.GetPoolAdminUserId()
			if err != nil {
				if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			myPrefix = utils.Int64ToStr(adminUserId) + "_"
		} else {
			myPrefix = ""
		}

		eConfig, err := d.GetMap(`SELECT * FROM e_config`, "name", "value")
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		confirmations := utils.StrToInt64(eConfig["confirmations"])
		mainDcAccount := utils.StrToInt64(eConfig["main_dc_account"])

		// все валюты, с которыми работаем
		currencyList, err := utils.EGetCurrencyList()
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}

		// ++++++++++++ reduction ++++++++++++

		// максимальный номер блока для процентов. Чтобы брать только новые
		maxReductionBlock, err := d.Single(`SELECT max(block_id) FROM e_reduction`).Int64()
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}

		// если есть свежая reduction, то нужно остановить торги
		reduction, err := d.Single(`SELECT block_id FROM reduction WHERE block_id > ? and pct > 0`, maxReductionBlock).Int64()
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		if reduction > 0 {
			err = d.ExecSql(`INSERT INTO e_reduction_lock (time) VALUES (?)`, utils.Time())
			if err != nil {
				log.Error("%v", utils.ErrInfo(err))
			}
		}

		// если уже прошло 10 блоков с момента обнаружения reduction, то производим сокращение объема монет
		rows, err := d.Query(d.FormatQuery(`SELECT pct, currency_id, time, block_id FROM reduction WHERE block_id > ? AND
	block_id < ?`), maxReductionBlock, blockId-confirmations)
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		for rows.Next() {
			var pct float64
			var currencyId, rTime, blockId int64
			err = rows.Scan(&pct, &currencyId, &rTime, &blockId)
			if err != nil {
				rows.Close()
				if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			//	$k = (100-$row['pct'])/100;
			k := (100 - pct) / 100
			// уменьшаем все средства на счетах
			err = d.ExecSql(`UPDATE e_wallets SET amount = amount * ? WHERE currency_id = ?`, k, currencyId)

			// уменьшаем все средства на вывод
			err = d.ExecSql(`UPDATE e_withdraw SET amount = amount * ? WHERE currency_id = ? AND close_time = 0`, k, currencyId)

			// уменьшаем все ордеры на продажу
			err = d.ExecSql(`UPDATE e_orders SET amount = amount * ?, begin_amount = begin_amount * ? WHERE sell_currency_id = ?`, k, k, currencyId)

			err = d.ExecSql(`INSERT INTO e_reduction (
					time,
					block_id,
					currency_id,
					pct
				)
				VALUES (
					?,
					?,
					?,
					?
				)`, rTime, blockId, currencyId, pct)
			if err != nil {
				rows.Close()
				if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
		}
		rows.Close()

		// ++++++++++++ DC ++++++++++++
		/*
		 * Важно! отключать в кроне при обнулении данных в БД
		 *
		 * 1. Получаем инфу о входящих переводах и начисляем их на счета юзеров
		 * 2. Обновляем проценты
		 * 3. Чистим кол-во отправленных смс-ок
		 * */
		nodePrivateKey, err := d.GetNodePrivateKey(myPrefix)
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		/*
		 * Получаем инфу о входящих переводах и начисляем их на счета юзеров
		 * */

		// если всё остановлено из-за найденного блока с reduction, то входящие переводы не обрабатываем
		reductionLock, err := utils.EGetReductionLock()
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		if reductionLock > 0 {
			if d.dPrintSleep(utils.ErrInfo("reductionLock"), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}

		rows, err = d.Query(d.FormatQuery(`
				SELECT amount, id, block_id, type_id, currency_id, to_user_id, time, comment, comment_status
				FROM my_dc_transactions
				WHERE type = 'from_user' AND
					  block_id < ? AND
					  exchange_checked = 0 AND
					  status = 'approved' AND
					  to_user_id = ?
				ORDER BY id DESC`), blockId-confirmations, mainDcAccount)
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		for rows.Next() {
			var amount float64
			var id, blockId, typeId, currencyId, toUserId, txTime int64
			var comment, commentStatus string
			err = rows.Scan(&amount, &id, &blockId, &typeId, &currencyId, &toUserId, &txTime, &comment, &commentStatus)
			if err != nil {
				rows.Close()
				if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			// отметим exchange_checked=1, чтобы больше не брать эту тр-ию
			err = d.ExecSql(`UPDATE my_dc_transactions SET exchange_checked = 1 WHERE id = ?`, id)
			if err != nil {
				rows.Close()
				if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}

			// вначале нужно проверить, точно ли есть такой перевод в блоке
			binaryData, err := d.Single(`SELECT data FROM block_chain WHERE id = ?`, blockId).Bytes()
			if err != nil {
				rows.Close()
				if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			p := new(dcparser.Parser)
			p.DCDB = d.DCDB
			p.BinaryData = binaryData
			p.ParseDataLite()
			for _, txMap := range p.TxMapArr {
				// пропускаем все ненужные тр-ии
				if utils.BytesToInt64(txMap["type"]) != utils.TypeInt("SendDc") {
					continue
				}
				log.Debug("md5hash %s", txMap["md5hash"])

				// если что-то случится с таблой my_dc_transactions, то все ввода на биржу будут зачислены по новой
				// поэтому нужно проверять e_adding_funds
				exists, err := d.Single(`SELECT id FROM e_adding_funds WHERE hex(tx_hash) = ?`, string(txMap["md5hash"])).Int64()
				if err != nil {
					rows.Close()
					if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				log.Debug("exists %d", exists)
				if exists != 0 {
					continue
				}

				log.Debug("user_id = %d / typeId = %d / currency_id = %d / currencyId = %d / amount = %f / amount = %f / comment = %s / comment = %s / to_user_id = %d / toUserId = %d ", utils.BytesToInt64(txMap["user_id"]), typeId, utils.BytesToInt64(txMap["currency_id"]), currencyId, utils.BytesToFloat64(txMap["amount"]), amount, string(utils.BinToHex(txMap["comment"])), comment, utils.BytesToInt64(txMap["to_user_id"]), toUserId)
				// сравнение данных из таблы my_dc_transactions с тем, что в блоке
				if utils.BytesToInt64(txMap["user_id"]) == typeId && utils.BytesToInt64(txMap["currency_id"]) == currencyId && utils.BytesToFloat64(txMap["amount"]) == amount && string(utils.BinToHex(txMap["comment"])) == comment && utils.BytesToInt64(txMap["to_user_id"]) == toUserId {

					decryptedComment := comment
					if commentStatus == "encrypted" {
						// расшифруем коммент
						block, _ := pem.Decode([]byte(nodePrivateKey))
						if block == nil || block.Type != "RSA PRIVATE KEY" {
							rows.Close()
							if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
								break BEGIN
							}
							continue BEGIN
						}
						private_key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
						if err != nil {
							rows.Close()
							if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
								break BEGIN
							}
							continue BEGIN
						}
						decryptedComment_, err := rsa.DecryptPKCS1v15(rand.Reader, private_key, utils.HexToBin(comment))
						if err != nil {
							rows.Close()
							if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
								break BEGIN
							}
							continue BEGIN
						}
						decryptedComment = string(decryptedComment_)
						// запишем расшифрованный коммент, чтобы потом можно было найти перевод в ручном режиме
						err = d.ExecSql("UPDATE "+myPrefix+"my_dc_transactions SET comment = ?, comment_status = 'decrypted' WHERE id = ?", decryptedComment, id)
						if err != nil {
							rows.Close()
							if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
								break BEGIN
							}
							continue BEGIN
						}
					}

					// возможно юзер сделал перевод в той валюте, которая у нас на бирже еще не торгуется
					if len(currencyList[currencyId]) == 0 {
						log.Error("currencyId %d not trading", currencyId)
						continue
					}

					// возможно, что чуть раньше было reduction, а это значит, что все тр-ии,
					// которые мы ещё не обработали и которые были До блока с reduction нужно принимать с учетом reduction
					// т.к. средства на нашем счете уже урезались, а  вот те, что после reduction - остались в том виде, в котором пришли
					lastReduction, err := d.OneRow("SELECT block_id, pct FROM reduction WHERE currency_id  = ? ORDER BY block_id", currencyId).Int64()
					if err != nil {
						rows.Close()
						if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
							break BEGIN
						}
						continue BEGIN
					}
					if blockId <= lastReduction["block_id"] {
						// сумму с учетом reduction
						k0 := (100 - lastReduction["pct"]) / 100
						amount = amount * float64(k0)
					}

					// начисляем средства на счет того, чей id указан в комменте
					r, _ := regexp.Compile(`(?i)\s*#\s*([0-9]+)\s*`)
					user := r.FindStringSubmatch(decryptedComment)
					if len(user) == 0 {
						log.Error("len(user) == 0")
						continue
					}
					log.Debug("user %s", user[1])
					// user_id с биржевой таблы
					uid := utils.StrToInt64(user[1])
					userAmountAndProfit := utils.EUserAmountAndProfit(uid, currencyId)
					newAmount_ := userAmountAndProfit + amount

					utils.UpdEWallet(uid, currencyId, utils.Time(), newAmount_, true)

					// для отчетности запишем в историю
					err = d.ExecSql(`
						INSERT INTO e_adding_funds (
							user_id,
							currency_id,
							time,
							amount,
							tx_hash
						)
						VALUES (
							?,
							?,
							?,
							?,
							?
						)`, uid, currencyId, txTime, amount, string(txMap["md5hash"]))
					if err != nil {
						rows.Close()
						if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
							break BEGIN
						}
						continue BEGIN
					}
				}
			}
		}
		rows.Close()

		/*
		 * Обновляем проценты
		 * */
		// максимальный номер блока для процентов. Чтобы брать только новые
		maxPctBlock, err := d.Single(`SELECT max(block_id) FROM e_user_pct`).Int64()

		log.Debug(`SELECT time, block_id, currency_id, user FROM pct WHERE  block_id < ` + utils.Int64ToStr(blockId-confirmations) + ` AND block_id > ` + utils.Int64ToStr(maxPctBlock))
		rows, err = d.Query(d.FormatQuery(`SELECT time, block_id, currency_id, user FROM pct WHERE  block_id < ? AND block_id > ?`), blockId-confirmations, maxPctBlock)
		if err != nil {
			if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		for rows.Next() {
			var pct float64
			var pTime, blockId, currencyId int64
			err = rows.Scan(&pTime, &blockId, &currencyId, &pct)
			if err != nil {
				rows.Close()
				if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			d.ExecSql(`
				INSERT INTO e_user_pct (
					time,
					block_id,
					currency_id,
					pct
				)
				VALUES (
					?,
					?,
					?,
					?
				)`, pTime, blockId, currencyId, pct)
		}
		rows.Close()

		if d.dSleep(d.sleepTime) {
			break BEGIN
		}
	}
	log.Debug("break BEGIN %v", GoroutineName)
}
Example #21
0
func BlocksCollection(chBreaker chan bool, chAnswer chan string) {
	defer func() {
		if r := recover(); r != nil {
			log.Error("daemon Recovered", r)
			panic(r)
		}
	}()

	const GoroutineName = "BlocksCollection"
	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 = 300
	} else {
		d.sleepTime = 60
	}
	if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) {
		return
	}
	d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName)
	if d.DCDB == nil {
		return
	}
	//var cur bool
BEGIN:
	for {
		log.Info(GoroutineName)
		MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())}

		// проверим, не нужно ли нам выйти из цикла
		if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) {
			break BEGIN
		}
		log.Debug("0")
		config, err := d.GetNodeConfig()
		if err != nil {
			if d.dPrintSleep(err, d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		log.Debug("1")

		err, restart := d.dbLock()
		if restart {
			log.Debug("restart true")
			break BEGIN
		}
		if err != nil {
			log.Debug("restart err %v", err)
			if d.dPrintSleep(err, d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}
		log.Debug("2")

		// если это первый запуск во время инсталяции
		currentBlockId, err := d.GetBlockId()
		if err != nil {
			if d.unlockPrintSleep(err, d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}

		log.Info("config", config)
		log.Info("currentBlockId", currentBlockId)

		// на время тестов
		/*if !cur {
		    currentBlockId = 0
		    cur = true
		}*/
		parser := new(dcparser.Parser)
		parser.DCDB = d.DCDB
		parser.GoroutineName = GoroutineName
		if currentBlockId == 0 || *utils.StartBlockId > 0 {
			/*
			   IsNotExistBlockChain := false
			   if _, err := os.Stat(*utils.Dir+"/public/blockchain"); os.IsNotExist(err) {
			       IsNotExistBlockChain = true
			   }*/
			if config["first_load_blockchain"] == "file" /* && IsNotExistBlockChain*/ {

				log.Info("first_load_blockchain=file")
				nodeConfig, err := d.GetNodeConfig()
				blockchain_url := nodeConfig["first_load_blockchain_url"]
				if len(blockchain_url) == 0 {
					blockchain_url = consts.BLOCKCHAIN_URL
				}
				log.Debug("blockchain_url: %s", blockchain_url)
				// возможно сервер отдаст блокчейн не с первой попытки
				var blockchainSize int64
				for i := 0; i < 10; i++ {
					log.Debug("blockchain_url: %s, i: %d", blockchain_url, i)
					blockchainSize, err = utils.DownloadToFile(blockchain_url, *utils.Dir+"/public/blockchain", 3600, chBreaker, chAnswer, GoroutineName)
					if err != nil {
						log.Error("%v", utils.ErrInfo(err))
					}
					if blockchainSize > consts.BLOCKCHAIN_SIZE {
						break
					}
				}
				log.Debug("blockchain dw ok")
				if err != nil || blockchainSize < consts.BLOCKCHAIN_SIZE {
					if err != nil {
						log.Error("%v", utils.ErrInfo(err))
					} else {
						log.Info(fmt.Sprintf("%v < %v", blockchainSize, consts.BLOCKCHAIN_SIZE))
					}
					if d.unlockPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}

				first := true
				/*// блокчейн мог быть загружен ранее. проверим его размер


				  stat, err := file.Stat()
				  if err != nil {
				      if d.unlockPrintSleep(err, d.sleepTime) {	break BEGIN }
				      file.Close()
				      continue BEGIN
				  }
				  if stat.Size() < consts.BLOCKCHAIN_SIZE {
				      d.unlockPrintSleep(fmt.Errorf("%v < %v", stat.Size(), consts.BLOCKCHAIN_SIZE), 1)
				      file.Close()
				      continue BEGIN
				  }*/

				log.Debug("GO!")
				file, err := os.Open(*utils.Dir + "/public/blockchain")
				if err != nil {
					if d.unlockPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				err = d.ExecSql(`UPDATE config SET current_load_blockchain = 'file'`)
				if err != nil {
					if d.unlockPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}

				for {
					// проверим, не нужно ли нам выйти из цикла
					if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) {
						d.unlockPrintSleep(fmt.Errorf("DaemonsRestart"), 0)
						break BEGIN
					}
					b1 := make([]byte, 5)
					file.Read(b1)
					dataSize := utils.BinToDec(b1)
					log.Debug("dataSize", dataSize)
					if dataSize > 0 {

						data := make([]byte, dataSize)
						file.Read(data)
						//log.Debug("data %x\n", data)
						blockId := utils.BinToDec(data[0:5])
						if *utils.EndBlockId > 0 && blockId == *utils.EndBlockId {
							if d.dPrintSleep(err, d.sleepTime) {
								break BEGIN
							}
							file.Close()
							continue BEGIN
						}
						log.Info("blockId", blockId)
						data2 := data[5:]
						length := utils.DecodeLength(&data2)
						log.Debug("length", length)
						//log.Debug("data2 %x\n", data2)
						blockBin := utils.BytesShift(&data2, length)
						//log.Debug("blockBin %x\n", blockBin)

						if *utils.StartBlockId == 0 || (*utils.StartBlockId > 0 && blockId > *utils.StartBlockId) {

							// парсинг блока
							parser.BinaryData = blockBin

							if first {
								parser.CurrentVersion = consts.VERSION
								first = false
							}
							err = parser.ParseDataFull()
							if err != nil {
								if d.dPrintSleep(err, d.sleepTime) {
									break BEGIN
								}
								file.Close()
								continue BEGIN
							}
							err = parser.InsertIntoBlockchain()
							if err != nil {
								if d.dPrintSleep(err, d.sleepTime) {
									break BEGIN
								}
								file.Close()
								continue BEGIN
							}

							// отметимся, чтобы не спровоцировать очистку таблиц
							err = parser.UpdMainLock()
							if err != nil {
								if d.dPrintSleep(err, d.sleepTime) {
									break BEGIN
								}
								file.Close()
								continue BEGIN
							}
							if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) {
								if d.dPrintSleep(err, d.sleepTime) {
									break BEGIN
								}
								file.Close()
								continue BEGIN
							}
						}
						// ненужный тут размер в конце блока данных
						data = make([]byte, 5)
						file.Read(data)
					} else {
						if d.unlockPrintSleep(err, d.sleepTime) {
							break BEGIN
						}
						continue BEGIN
					}
					// utils.Sleep(1)
				}
				file.Close()
			} else {

				newBlock, err := static.Asset("static/1block.bin")
				if err != nil {
					if d.dPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				parser.BinaryData = newBlock
				parser.CurrentVersion = consts.VERSION

				err = parser.ParseDataFull()
				if err != nil {
					if d.dPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				err = parser.InsertIntoBlockchain()

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

			utils.Sleep(1)
			d.dbUnlock()
			continue BEGIN
		}
		d.dbUnlock()

		err = d.ExecSql(`UPDATE config SET current_load_blockchain = 'nodes'`)
		if err != nil {
			if d.unlockPrintSleep(err, d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}

		myConfig, err := d.OneRow("SELECT local_gate_ip, static_node_user_id FROM config").String()
		if err != nil {
			if d.dPrintSleep(err, d.sleepTime) {
				break BEGIN
			}
			continue
		}
		var hosts []map[string]string
		var nodeHost string
		var dataTypeMaxBlockId, dataTypeBlockBody int64
		if len(myConfig["local_gate_ip"]) > 0 {
			hosts = append(hosts, map[string]string{"host": myConfig["local_gate_ip"], "user_id": myConfig["static_node_user_id"]})
			nodeHost, err = d.Single("SELECT tcp_host FROM miners_data WHERE user_id  =  ?", myConfig["static_node_user_id"]).String()
			if err != nil {
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue
			}
			dataTypeMaxBlockId = 9
			dataTypeBlockBody = 8
			//getBlockScriptName = "ajax?controllerName=protectedGetBlock";
			//addNodeHost = "&nodeHost="+nodeHost;
		} else {
			// получим список нодов, с кем установлено рукопожатие
			hosts, err = d.GetAll("SELECT * FROM nodes_connection", -1)
			if err != nil {
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue
			}
			dataTypeMaxBlockId = 10
			dataTypeBlockBody = 7
			//getBlockScriptName = "ajax?controllerName=getBlock";
			//addNodeHost = "";
		}

		log.Info("%v", hosts)

		if len(hosts) == 0 {
			if d.dPrintSleep(err, 1) {
				break BEGIN
			}
			continue
		}

		maxBlockId := int64(1)
		maxBlockIdHost := ""
		var maxBlockIdUserId int64
		// получим максимальный номер блока
		for i := 0; i < len(hosts); i++ {
			if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) {
				break BEGIN
			}
			conn, err := utils.TcpConn(hosts[i]["host"])
			if err != nil {
				if d.dPrintSleep(err, 1) {
					break BEGIN
				}
				continue
			}
			// шлем тип данных
			_, err = conn.Write(utils.DecToBin(dataTypeMaxBlockId, 1))
			if err != nil {
				conn.Close()
				if d.dPrintSleep(err, 1) {
					break BEGIN
				}
				continue
			}
			if len(nodeHost) > 0 { // защищенный режим
				err = utils.WriteSizeAndData([]byte(nodeHost), conn)
				if err != nil {
					conn.Close()
					if d.dPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue
				}
			}
			// в ответ получаем номер блока
			blockIdBin := make([]byte, 4)
			_, err = conn.Read(blockIdBin)
			if err != nil {
				conn.Close()
				if d.dPrintSleep(err, 1) {
					break BEGIN
				}
				continue
			}
			conn.Close()
			id := utils.BinToDec(blockIdBin)
			if id > maxBlockId || i == 0 {
				maxBlockId = id
				maxBlockIdHost = hosts[i]["host"]
				maxBlockIdUserId = utils.StrToInt64(hosts[i]["user_id"])
			}
			if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) {
				utils.Sleep(1)
				break BEGIN
			}
		}

		// получим наш текущий имеющийся номер блока
		// ждем, пока разлочится и лочим сами, чтобы не попасть в тот момент, когда данные из блока уже занесены в БД, а info_block еще не успел обновиться
		err, restart = d.dbLock()
		if restart {
			break BEGIN
		}
		if err != nil {
			if d.dPrintSleep(err, d.sleepTime) {
				break BEGIN
			}
			continue BEGIN
		}

		currentBlockId, err = d.Single("SELECT block_id FROM info_block").Int64()
		if err != nil {
			if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
				break BEGIN
			}
			continue
		}
		log.Info("currentBlockId", currentBlockId, "maxBlockId", maxBlockId)
		if maxBlockId <= currentBlockId {
			if d.unlockPrintSleep(utils.ErrInfo(errors.New("maxBlockId <= currentBlockId")), d.sleepTime) {
				break BEGIN
			}
			continue
		}

		fmt.Printf("\nnode: %s\n", maxBlockIdHost)

		// в цикле собираем блоки, пока не дойдем до максимального
		for blockId := currentBlockId + 1; blockId < maxBlockId+1; blockId++ {
			d.UpdMainLock()
			if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				break BEGIN
			}
			variables, err := d.GetAllVariables()
			if err != nil {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			// качаем тело блока с хоста maxBlockIdHost
			binaryBlock, err := utils.GetBlockBody(maxBlockIdHost, blockId, dataTypeBlockBody, nodeHost)

			if len(binaryBlock) == 0 {
				// баним на 1 час хост, который дал нам пустой блок, хотя должен был дать все до максимального
				// для тестов убрал, потом вставить.
				//nodes_ban ($db, $max_block_id_user_id, substr($binary_block, 0, 512)."\n".__FILE__.', '.__LINE__.', '. __FUNCTION__.', '.__CLASS__.', '. __METHOD__);
				//p.NodesBan(maxBlockIdUserId, "len(binaryBlock) == 0")
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			binaryBlockFull := binaryBlock
			utils.BytesShift(&binaryBlock, 1) // уберем 1-й байт - тип (блок/тр-я)
			// распарсим заголовок блока
			blockData := utils.ParseBlockHeader(&binaryBlock)
			log.Info("blockData: %v, blockId: %v", blockData, blockId)

			// если существуют глючная цепочка, тот тут мы её проигнорируем
			badBlocks_, err := d.Single("SELECT bad_blocks FROM config").Bytes()
			if err != nil {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			badBlocks := make(map[int64]string)
			if len(badBlocks_) > 0 {
				err = json.Unmarshal(badBlocks_, &badBlocks)
				if err != nil {
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
			}
			if badBlocks[blockData.BlockId] == string(utils.BinToHex(blockData.Sign)) {
				d.NodesBan(maxBlockIdUserId, fmt.Sprintf("bad_block = %v => %v", blockData.BlockId, badBlocks[blockData.BlockId]))
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}

			// размер блока не может быть более чем max_block_size
			if currentBlockId > 1 {
				if int64(len(binaryBlock)) > variables.Int64["max_block_size"] {
					d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`len(binaryBlock) > variables.Int64["max_block_size"]  %v > %v`, len(binaryBlock), variables.Int64["max_block_size"]))
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
			}

			if blockData.BlockId != blockId {
				d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`blockData.BlockId != blockId  %v > %v`, blockData.BlockId, blockId))
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}

			// нам нужен хэш предыдущего блока, чтобы проверить подпись
			prevBlockHash := ""
			if blockId > 1 {
				prevBlockHash, err = d.Single("SELECT hash FROM block_chain WHERE id = ?", blockId-1).String()
				if err != nil {
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				prevBlockHash = string(utils.BinToHex([]byte(prevBlockHash)))
			} else {
				prevBlockHash = "0"
			}
			first := false
			if blockId == 1 {
				first = true
			}
			// нам нужен меркель-рут текущего блока
			mrklRoot, err := utils.GetMrklroot(binaryBlock, variables, first)
			if err != nil {
				d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`%v`, err))
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}

			// публичный ключ того, кто этот блок сгенерил
			nodePublicKey, err := d.GetNodePublicKey(blockData.UserId)
			if err != nil {
				if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}

			// SIGN от 128 байта до 512 байт. Подпись от TYPE, BLOCK_ID, PREV_BLOCK_HASH, TIME, USER_ID, LEVEL, MRKL_ROOT
			forSign := fmt.Sprintf("0,%v,%v,%v,%v,%v,%s", blockData.BlockId, prevBlockHash, blockData.Time, blockData.UserId, blockData.Level, mrklRoot)

			// проверяем подпись
			if !first {
				_, err = utils.CheckSign([][]byte{nodePublicKey}, forSign, blockData.Sign, true)
			}

			// качаем предыдущие блоки до тех пор, пока отличается хэш предыдущего.
			// другими словами, пока подпись с prevBlockHash будет неверной, т.е. пока что-то есть в $error
			if err != nil {
				log.Error("%v", utils.ErrInfo(err))
				if blockId < 1 {
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				// нужно привести данные в нашей БД в соответствие с данными у того, у кого качаем более свежий блок
				//func (p *Parser) GetOldBlocks (userId, blockId int64, host string, hostUserId int64, goroutineName, getBlockScriptName, addNodeHost string) error {
				err := parser.GetOldBlocks(blockData.UserId, blockId-1, maxBlockIdHost, maxBlockIdUserId, GoroutineName, dataTypeBlockBody, nodeHost)
				if err != nil {
					log.Error("%v", err)
					d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`blockId: %v / %v`, blockId, err))
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}

			} else {

				log.Info("plug found blockId=%v\n", blockId)

				// получим наши транзакции в 1 бинарнике, просто для удобства
				var transactions []byte
				utils.WriteSelectiveLog("SELECT data FROM transactions WHERE verified = 1 AND used = 0")
				rows, err := d.Query("SELECT data FROM transactions WHERE verified = 1 AND used = 0")
				if err != nil {
					utils.WriteSelectiveLog(err)
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				for rows.Next() {
					var data []byte
					err = rows.Scan(&data)
					utils.WriteSelectiveLog(utils.BinToHex(data))
					if err != nil {
						rows.Close()
						if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
							break BEGIN
						}
						continue BEGIN
					}
					transactions = append(transactions, utils.EncodeLengthPlusData(data)...)
				}
				rows.Close()
				if len(transactions) > 0 {
					// отмечаем, что эти тр-ии теперь нужно проверять по новой
					utils.WriteSelectiveLog("UPDATE transactions SET verified = 0 WHERE verified = 1 AND used = 0")
					affect, err := d.ExecSqlGetAffect("UPDATE transactions SET verified = 0 WHERE verified = 1 AND used = 0")
					if err != nil {
						utils.WriteSelectiveLog(err)
						if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
							break BEGIN
						}
						continue BEGIN
					}
					utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect))
					// откатываем по фронту все свежие тр-ии
					parser.BinaryData = transactions
					err = parser.ParseDataRollbackFront(false)
					if err != nil {
						utils.Sleep(1)
						continue BEGIN
					}
				}

				err = parser.RollbackTransactionsTestblock(true)
				if err != nil {
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				err = d.ExecSql("DELETE FROM testblock")
				if err != nil {
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
			}

			// теперь у нас в таблицах всё тоже самое, что у нода, у которого качаем блок
			// и можем этот блок проверить и занести в нашу БД
			parser.BinaryData = binaryBlockFull
			err = parser.ParseDataFull()
			if err == nil {
				err = parser.InsertIntoBlockchain()
				if err != nil {
					if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
			}
			// начинаем всё с начала уже с другими нодами. Но у нас уже могут быть новые блоки до $block_id, взятые от нода, которого с в итоге мы баним
			if err != nil {
				d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`blockId: %v / %v`, blockId, err))
				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)
}
Example #22
0
func (c *Controller) BlockExplorer() (string, error) {

	var err error

	blockId := int64(utils.StrToFloat64(c.Parameters["blockId"]))
	start := int64(utils.StrToFloat64(c.Parameters["start"]))

	var data, sql string
	if start > 0 || (start == 0 && blockId == 0) {
		if start == 0 && blockId == 0 {
			data += "<h3>Latest Blocks</h3>"
			sql = `	SELECT data,  hash
						FROM block_chain
						ORDER BY id DESC
						LIMIT 15`
		} else {
			sql = `	SELECT data,  hash
						FROM block_chain
						ORDER BY id ASC
						LIMIT ` + utils.Int64ToStr(start-1) + `, 100`
		}
		data += `<table class="table"><tr><th>Block</th><th>Hash</th><th>Time</th><th><nobr>User id</nobr></th><th><nobr>Miner id</nobr></th><th>Level</th><th>Transactions</th></tr>`
		blocksChain, err := c.GetAll(sql, -1)
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		for _, blockData := range blocksChain {
			hash := utils.BinToHex([]byte(blockData["hash"]))
			binaryData := []byte(blockData["data"])
			parser := new(dcparser.Parser)
			parser.DCDB = c.DCDB
			parser.BinaryData = binaryData
			err = parser.ParseDataLite()
			parser.BlockData.Sign = utils.BinToHex(parser.BlockData.Sign)
			minerId, err := c.GetMinerId(parser.BlockData.UserId)
			if err != nil {
				return "", utils.ErrInfo(err)
			}
			data += fmt.Sprintf(`<tr><td><a href="#" onclick="dc_navigate('blockExplorer', {'blockId':%d})">%d</a></td><td>%s</td><td><nobr><span class='unixtime'>%d</span></nobr></td><td>%d</td><td>%d</td><td>%d</td><td>`, parser.BlockData.BlockId, parser.BlockData.BlockId, hash, parser.BlockData.Time, parser.BlockData.UserId, minerId, parser.BlockData.Level)
			data += utils.IntToStr(len(parser.TxMapArr))
			data += "</td></tr>"
		}
		data += "</table>"
	} else if blockId > 0 {
		data += `<table class="table">`
		blockChain, err := c.OneRow("SELECT data, hash, cur_0l_miner_id, max_miner_id FROM block_chain WHERE id = ?", blockId).String()
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		binToHexArray := []string{"sign", "public_key", "encrypted_message", "comment", "bin_public_keys"}
		hash := utils.BinToHex([]byte(blockChain["hash"]))
		binaryData := blockChain["data"]
		parser := new(dcparser.Parser)
		parser.DCDB = c.DCDB
		parser.BinaryData = []byte(binaryData)
		err = parser.ParseDataLite()
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		parser.BlockData.Sign = utils.BinToHex(parser.BlockData.Sign)
		previous := parser.BlockData.BlockId - 1
		next := parser.BlockData.BlockId + 1
		levelsRange := utils.GetBlockGeneratorMinerIdRange(utils.StrToInt64(blockChain["cur_0l_miner_id"]), utils.StrToInt64(blockChain["max_miner_id"]))
		minerId, err := c.GetMinerId(parser.BlockData.UserId)
		if err != nil {
			return "", utils.ErrInfo(err)
		}

		_, _, _, CurrentUserId, _, _, _ := c.TestBlock()
		maxMinerId, err := c.Single("SELECT max(miner_id) FROM miners").Int64()
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		currentMinerId, err := c.Single("SELECT miner_id FROM miners_data WHERE user_id = ?", CurrentUserId).Int64()
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		NextBlockLevelsRange := utils.GetBlockGeneratorMinerIdRange(currentMinerId, maxMinerId)

		data += fmt.Sprintf(`<tr><td><strong>Raw&nbsp;data</strong></td><td><a href='ajax?controllerName=getBlock&id=%d&download=1' target='_blank'>Download</a></td></tr>`, parser.BlockData.BlockId)
		data += fmt.Sprintf(`<tr><td><strong>Block_id</strong></td><td>%d (<a href="#" onclick="dc_navigate('blockExplorer', {'blockId':%d})">Previous</a> / <a href="#" onclick="dc_navigate('blockExplorer', {'blockId':%d})">Next</a> )</td></tr>`, parser.BlockData.BlockId, previous, next)
		data += fmt.Sprintf(`<tr><td><strong>Hash</strong></td><td>%s</td></tr>`, hash)
		data += fmt.Sprintf(`<tr><td><strong>Time</strong></td><td><span class='unixtime'>%d</span> / %d</td></tr>`, parser.BlockData.Time, parser.BlockData.Time)
		data += fmt.Sprintf(`<tr><td><strong>User_id</strong></td><td>%d</td></tr>`, parser.BlockData.UserId)
		data += fmt.Sprintf(`<tr><td><strong>Miner_Id</strong></td><td>%d</td></tr>`, minerId)
		data += fmt.Sprintf(`<tr><td><strong>Level</strong></td><td>%d (%v) next: %v</td></tr>`, parser.BlockData.Level, levelsRange, NextBlockLevelsRange)
		data += fmt.Sprintf(`<tr><td><strong>Sign</strong></td><td>%s</td></tr>`, parser.BlockData.Sign)
		if len(parser.TxMapArr) > 0 {
			data += `<tr><td><strong>Transactions</strong></td><td><div><pre style='width: 700px'>`
			for i := 0; i < len(parser.TxMapArr); i++ {
				for k, data_ := range parser.TxMapArr[i] {
					if utils.InSliceString(k, binToHexArray) {
						parser.TxMapArr[i][k] = utils.BinToHex(data_)
					}
					if k == "file" {
						parser.TxMapArr[i][k] = []byte("file size: " + utils.IntToStr(len(data_)))
					} else if k == "code" {
						parser.TxMapArr[i][k] = utils.DSha256(data_)
					} else if k == "secret" {
						parser.TxMapArr[i][k] = utils.BinToHex(data_)
					}
					data += fmt.Sprintf("%v : %s\n", k, parser.TxMapArr[i][k])
				}
				data += "\n\n"
			}

			data += "</pre></div></td></tr>"
		}
		data += "</table>"
	}

	// пока панель тут
	myNotice := make(map[string]string)
	if c.SessUserId > 0 {
		myNotice, err = c.GetMyNoticeData(c.SessUserId, c.SessUserId, c.MyPrefix, c.Lang)
		if err != nil {
			return "", utils.ErrInfo(err)
		}
	}

	TemplateStr, err := makeTemplate("block_explorer", "blockExplorer", &BlockExplorerPage{
		Lang:           c.Lang,
		CurrencyList:   c.CurrencyListCf,
		MyNotice:       myNotice,
		Data:           data,
		Start:          start,
		BlockId:        blockId,
		PoolAdmin:      c.PoolAdmin,
		SessRestricted: c.SessRestricted,
		UserId:         c.SessUserId})
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	return TemplateStr, nil
}
Example #23
0
func (p *Parser) CashRequestOut() error {

	// возможно нужно обновить таблицу points_status
	err := p.pointsUpdateMain(p.TxMaps.Int64["to_user_id"])
	if err != nil {
		return p.ErrInfo(err)
	}

	// у получателя запроса останавливается майнинг по всем валютам и статусам, т.е. mining/pending. значит необходимо обновить tdc_amount и tdc_amount_update
	// WOC продолжает расти
	// обновление нужно, только если данный cash_request единственный с pending, иначе делать пересчет tdc_amount нельзя, т.к. уже были ранее пересчитаны
	existsRequests := p.CheckCashRequests(p.TxMaps.Int64["to_user_id"])
	if existsRequests == nil {
		log.Debug("updPromisedAmounts=", existsRequests)
		err = p.updPromisedAmounts(p.TxMaps.Int64["to_user_id"], true, true, p.BlockData.Time)
		if err != nil {
			return p.ErrInfo(err)
		}
	} else {
		// записываем cash_request_out_time во всех обещанных суммах, после того, как юзер вызвал актуализацию. акутализацию юзер вызывал т.к. у него есть непогашенные cash_request.
		log.Debug("updPromisedAmountsCashRequestOutTime")
		err = p.updPromisedAmountsCashRequestOutTime(p.TxMaps.Int64["to_user_id"])
		if err != nil {
			return p.ErrInfo(err)
		}
	}
	// пишем запрос в БД
	cashRequestId, err := p.ExecSqlGetLastInsertId("INSERT INTO cash_requests ( time, from_user_id, to_user_id, currency_id, amount, hash_code ) VALUES ( ?, ?, ?, ?, ?, [hex] )", "id", p.BlockData.Time, p.TxUserID, p.TxMaps.Int64["to_user_id"], p.TxMaps.Int64["currency_id"], p.TxMaps.Money["amount"], p.TxMaps.String["hash_code"])
	if err != nil {
		return p.ErrInfo(err)
	}

	// а может быть наш юзер - получатель запроса
	myUserId, myBlockId, myPrefix, _, err := p.GetMyUserId(p.TxMaps.Int64["to_user_id"])
	if err != nil {
		return err
	}
	if p.TxMaps.Int64["to_user_id"] == myUserId && myBlockId <= p.BlockData.BlockId {
		// пишем с таблу инфу, что к нам пришел новый запрос
		err = p.ExecSql("INSERT INTO "+myPrefix+"my_cash_requests ( time, to_user_id, currency_id, amount, comment, comment_status, status, hash_code, cash_request_id ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )", p.BlockData.Time, p.TxMaps.Int64["to_user_id"], p.TxMaps.Int64["currency_id"], p.TxMaps.Money["amount"], utils.BinToHex(p.TxMap["comment"]), "encrypted", "pending", p.TxMaps.String["hash_code"], cashRequestId)
		if err != nil {
			return p.ErrInfo(err)
		}
	}

	// или отправитель запроса - наш юзер
	myUserId, myBlockId, myPrefix, _, err = p.GetMyUserId(p.TxUserID)
	if err != nil {
		return err
	}
	if p.TxUserID == myUserId && myBlockId <= p.BlockData.BlockId {
		myId, err := p.Single("SELECT id FROM "+myPrefix+"my_cash_requests WHERE to_user_id  =  ? AND status  =  'my_pending' ORDER BY id DESC", p.TxMaps.Int64["to_user_id"]).Int64()
		if err != nil {
			return p.ErrInfo(err)
		}
		if myId > 0 {
			// обновим статус в нашей локальной табле.
			// у юзера может быть только 1 запрос к 1 юзеру со статусом my_pending
			err = p.ExecSql("UPDATE "+myPrefix+"my_cash_requests SET status = 'pending', time = ?, cash_request_id = ? WHERE id = ?", p.BlockData.Time, cashRequestId, myId)
			if err != nil {
				return p.ErrInfo(err)
			}
		} else {
			err = p.ExecSql("INSERT INTO "+myPrefix+"my_cash_requests ( to_user_id, currency_id, amount, comment, hash_code, status, cash_request_id ) VALUES ( ?, ?, ?, ?, ?, ?, ? )", p.TxMaps.Int64["to_user_id"], p.TxMaps.Int64["currency_id"], p.TxMaps.Money["amount"], "", p.TxMaps.String["hash_code"], "pending", cashRequestId)
			if err != nil {
				return p.ErrInfo(err)
			}
		}

		myId, err = p.Single("SELECT id FROM "+myPrefix+"my_dc_transactions WHERE status  =  'pending' AND type  =  'cash_request' AND to_user_id  =  ? AND amount  =  ? AND currency_id  =  ?", p.TxMaps.Int64["to_user_id"], p.TxMaps.Money["amount"], p.TxMaps.Int64["currency_id"]).Int64()
		if err != nil {
			return p.ErrInfo(err)
		}
		if myId > 0 {
			// чтобы при вызове update_sender_wallet из cash_request_in можно было обновить my_dc_transactions, т.к. там в WHERE есть type_id
			err = p.ExecSql("UPDATE "+myPrefix+"my_dc_transactions SET type_id=?, time = ? WHERE id = ?", cashRequestId, p.BlockData.Time, myId)
			if err != nil {
				return p.ErrInfo(err)
			}
		} else {
			err = p.ExecSql("INSERT INTO "+myPrefix+"my_dc_transactions ( status, type, type_id, to_user_id, amount, currency_id, comment, comment_status ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )", "pending", "cash_request", cashRequestId, p.TxMaps.Int64["to_user_id"], p.TxMaps.Money["amount"], p.TxMaps.Int64["currency_id"], utils.BinToHex(p.TxMap["comment"]), "encrypted")
			if err != nil {
				return p.ErrInfo(err)
			}
		}
	}
	return nil
}
Example #24
0
func (p *Parser) CashRequestOutFront() error {

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

	verifyData := map[string]string{"to_user_id": "bigint", "currency_id": "currency_id", "amount": "amount", "comment": "comment", "hash_code": "sha256"}
	err = p.CheckInputData(verifyData)
	if err != nil {
		return p.ErrInfo(err)
	}

	// нельзя слать запрос на woc
	if p.TxMaps.Int64["currency_id"] == 1 {
		return p.ErrInfo("WOC")
	}

	// прошло ли 30 дней с момента регистрации майнера
	minerNewbie := p.checkMinerNewbie()
	if minerNewbie != nil {
		// возможно, что майнер отдал наличные за DC и у него есть общенные суммы с repaid
		// нужно дать возможность вывести ровно столько, сколько он отдал
		repaidAmount, err := p.GetRepaidAmount(p.TxMaps.Int64["currency_id"], p.TxUserID)
		// сколько уже получил наличных
		amountCashRequests, err := p.Single("SELECT sum(amount) FROM cash_requests WHERE status  =  'approved' AND currency_id  =  ? AND from_user_id  =  ?", p.TxMaps.Int64["currency_id"], p.TxUserID).Float64()
		if err != nil {
			return p.ErrInfo(err)
		}
		if amountCashRequests+p.TxMaps.Money["amount"] > repaidAmount {
			return p.ErrInfo(fmt.Sprintf("%f + %f > %f", amountCashRequests, p.TxMaps.Money["amount"], repaidAmount))
		}
	}

	forSign := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", p.TxMap["type"], p.TxMap["time"], p.TxMap["user_id"], p.TxMap["to_user_id"], p.TxMap["amount"], utils.BinToHex(p.TxMap["comment"]), p.TxMap["currency_id"], p.TxMap["hash_code"])
	CheckSignResult, err := utils.CheckSign(p.PublicKeys, forSign, p.TxMap["sign"], false)
	if err != nil {
		return p.ErrInfo(err)
	}
	if !CheckSignResult {
		return p.ErrInfo("incorrect sign")
	}

	// проверим, существует ли такая валюта в таблице DC-валют
	if ok, err := p.CheckCurrency(p.TxMaps.Int64["currency_id"]); !ok {
		return p.ErrInfo(err)
	}

	// ===  begin проверка to_user_id

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

	maxPromisedAmount, err := p.GetMaxPromisedAmount(p.TxMaps.Int64["currency_id"])
	if err != nil {
		return p.ErrInfo(err)
	}

	repaidAmount, err := p.GetRepaidAmount(p.TxMaps.Int64["currency_id"], p.TxMaps.Int64["to_user_id"])
	if err != nil {
		return p.ErrInfo(err)
	}
	if p.TxMaps.Money["amount"]+repaidAmount > maxPromisedAmount {
		return p.ErrInfo(fmt.Sprintf("%f + %f > %f", p.TxMaps.Money["amount"], repaidAmount, maxPromisedAmount))
	}

	// не даем превысить общий лимит
	promisedAmount, err := p.Single("SELECT amount FROM promised_amount WHERE status  =  'mining' AND currency_id  =  ? AND user_id  =  ? AND del_block_id  =  0 AND del_mining_block_id  =  0", p.TxMaps.Int64["currency_id"], p.TxMaps.Int64["to_user_id"]).Float64()
	if err != nil {
		return p.ErrInfo(err)
	}
	rest := maxPromisedAmount - repaidAmount
	if rest < promisedAmount {
		promisedAmount = rest
	}

	// минимальная сумма. теоретически может делиться на min_promised_amount пока не достигнет 0.01
	if p.TxMaps.Money["amount"] < promisedAmount/float64(p.Variables.Int64["min_promised_amount"]) {
		return p.ErrInfo(fmt.Sprintf("%f < %f / %d", p.TxMaps.Money["amount"], promisedAmount, p.Variables.Int64["min_promised_amount"]))
	}
	if p.TxMaps.Money["amount"] < 0.01 {
		return p.ErrInfo("amount<0.01")
	}

	var txTime int64
	if p.BlockData != nil { // тр-ия пришла в блоке
		txTime = p.BlockData.Time
	} else {
		txTime = time.Now().Unix() - 30 // просто на всякий случай небольшой запас
	}

	// Чтобы не задалбывать получателей запроса на обмен, не даем отправить следующий запрос, пока не пройдет cash_request_time сек с момента предыдущего
	cashRequestPending, err := p.Single("SELECT status FROM cash_requests WHERE to_user_id  =  ? AND del_block_id  =  0 AND for_repaid_del_block_id  =  0 AND time > ? AND status  =  'pending'", p.TxMaps.Int64["to_user_id"], (txTime - p.Variables.Int64["cash_request_time"])).String()
	if err != nil {
		return p.ErrInfo(err)
	}
	if len(cashRequestPending) > 0 {
		return p.ErrInfo("cash_requests status not null")
	}

	// не находится ли юзер в данный момент на каникулах.
	rows, err := p.Query(p.FormatQuery("SELECT start_time, end_time FROM holidays WHERE user_id = ? AND del = 0"), p.TxMaps.Int64["to_user_id"])
	if err != nil {
		return p.ErrInfo(err)
	}
	defer rows.Close()
	for rows.Next() {
		var startTime, endTime int64
		err = rows.Scan(&startTime, &endTime)
		if err != nil {
			return p.ErrInfo(err)
		}
		var time1, time2 int64
		if p.BlockData != nil {
			time1 = p.BlockData.Time
			time2 = time1
		} else {
			// тут используем time() с запасом 1800 сек, т.к. в момент, когда тр-ия попадет в блок, каникулы уже могут начаться.
			// т.е. у голой тр-ии проверка идет жестче
			time1 = time.Now().Unix() + 1800
			time2 = time.Now().Unix()
		}
		if startTime <= time1 && endTime >= time2 {
			return p.ErrInfo("error holidays")
		}
	}
	// === end проверка to_user_id

	// ===  begin проверка отправителя
	// является ли данный юзер майнером
	err = p.checkMiner(p.TxUserID)
	if err != nil {
		return p.ErrInfo(err)
	}
	/*
	 * WalletsBuffer тут не используем т.к. попадение 2-х тр-ий данного типа в 1 блок во время генарции блока исключается в clear_incompatible_tx.
	 * там же исключается попадение данного типа с new_forex и пр.
	 * А проверка 2-го списания идет в ParseDataFull
	 * */
	if p.BlockData != nil && p.BlockData.BlockId > 173941 {
		// в блоке 173941 была попытка отправить 2 запроса на 408 и 200 dUSD, в то время как на кошельке было только 449.6
		// в итоге check_sender_money возвращало ошибку
		// есть ли нужная сумма на кошельке
		p.TxMaps.Int64["from_user_id"] = p.TxMaps.Int64["user_id"]
		for i := 0; i < 5; i++ {
			p.TxMaps.Money["arbitrator"+utils.IntToStr(i)+"_commission"] = 0
		}
		p.TxMaps.Money["commission"] = 0
		//func (p *Parser) checkSenderMoney(currencyId, fromUserId int64, amount, commission, arbitrator0_commission, arbitrator1_commission, arbitrator2_commission, arbitrator3_commission, arbitrator4_commission float64) (float64, error) {
		_, err := p.checkSenderMoney(p.TxMaps.Int64["currency_id"], p.TxMaps.Int64["from_user_id"], p.TxMaps.Money["amount"], p.TxMaps.Money["commission"], p.TxMaps.Money["arbitrator0_commission"], p.TxMaps.Money["arbitrator1_commission"], p.TxMaps.Money["arbitrator2_commission"], p.TxMaps.Money["arbitrator3_commission"], p.TxMaps.Money["arbitrator4_commission"])
		if err != nil {
			return p.ErrInfo(err)
		}
	}
	// У юзера не должно быть cash_requests со статусом pending
	err = p.CheckCashRequests(p.TxUserID)
	if err != nil {
		return p.ErrInfo(err)
	}

	err = p.limitRequest(p.Variables.Int64["limit_cash_requests_out"], "cash_requests", p.Variables.Int64["limit_cash_requests_out_period"])
	if err != nil {
		return p.ErrInfo(err)
	}
	// ===  end проверка отправителя

	return nil
}
Example #25
0
func (p *Parser) MoneyBackRequest() error {

	err := p.selectiveLoggingAndUpd([]string{"status"}, []interface{}{"refund"}, "orders", []string{"id"}, []string{utils.Int64ToStr(p.TxMaps.Int64["order_id"])})
	if err != nil {
		return p.ErrInfo(err)
	}

	orderData, err := p.OneRow("SELECT seller, arbitrator0, arbitrator1, arbitrator2, arbitrator3, arbitrator4 FROM orders WHERE id  =  ?", p.TxMaps.Int64["order_id"]).Int64()
	if err != nil {
		return p.ErrInfo(err)
	}

	// проверим, не является ли мы продавцом или арбитром
	myUserId, _, myPrefix, _, err := p.GetMyUserId(orderData["seller"])
	if err != nil {
		return p.ErrInfo(err)
	}
	if orderData["seller"] == myUserId {
		err = p.ExecSql("INSERT INTO "+myPrefix+"my_comments ( type, id, comment, comment_status ) VALUES ( 'seller', ?, ?, 'encrypted' )", p.TxMaps.Int64["order_id"], utils.BinToHex(p.TxMap["seller_enc_text"]))
		if err != nil {
			return p.ErrInfo(err)
		}
	}
	for i := 0; i < 5; i++ {
		iStr := utils.IntToStr(i)
		if orderData["arbitrator"+iStr] == 0 {
			continue
		}
		myUserId, _, myPrefix, _, err := p.GetMyUserId(orderData["arbitrator"+iStr])
		if err != nil {
			return p.ErrInfo(err)
		}
		if orderData["arbitrator"+iStr] == myUserId {
			err = p.ExecSql("INSERT INTO "+myPrefix+"my_comments ( type, id, comment, comment_status ) VALUES ( 'arbitrator', ?, ?, 'encrypted' )", p.TxMaps.Int64["order_id"], utils.BinToHex(p.TxMaps.Bytes["arbitrator"+iStr+"_enc_text"]))
			if err != nil {
				return p.ErrInfo(err)
			}
		}
	}

	return nil
}
Example #26
0
func (p *Parser) AutoPayment() error {

	autoPaymentData, err := p.OneRow(`
			SELECT commission, amount, currency_id, recipient
			FROM auto_payments
			WHERE id = ?
			LIMIT 1
			`, p.TxMaps.Int64["auto_payment_id"]).String()
	if err != nil {
		return p.ErrInfo(err)
	}
	commission := utils.StrToFloat64(autoPaymentData["commission"])
	amount := utils.StrToFloat64(autoPaymentData["amount"])
	currencyId := utils.StrToInt64(autoPaymentData["currency_id"])
	recipient := utils.StrToInt64(autoPaymentData["recipient"])

	// 1 возможно нужно обновить таблицу points_status
	err = p.pointsUpdateMain(p.BlockData.UserId)
	if err != nil {
		return p.ErrInfo(err)
	}
	// 2
	err = p.pointsUpdateMain(p.TxUserID)
	if err != nil {
		return p.ErrInfo(err)
	}
	// 3
	err = p.pointsUpdateMain(recipient)
	if err != nil {
		return p.ErrInfo(err)
	}

	// 4 обновим сумму на кошельке отправителя, залогировав предыдущее значение
	err = p.updateSenderWallet(p.TxUserID, currencyId, amount, commission, "from_user", recipient, recipient, string(utils.BinToHex(p.TxMap["comment"])), "encrypted")
	if err != nil {
		return p.ErrInfo(err)
	}

	log.Debug("AutoPayment updateRecipientWallet")
	// 5 обновим сумму на кошельке получателю
	err = p.updateRecipientWallet(recipient, currencyId, amount, "from_user", p.TxUserID, p.TxMaps.String["comment"], "encrypted", true)
	if err != nil {
		return p.ErrInfo(err)
	}

	// 6 теперь начисляем комиссию майнеру, который этот блок сгенерил
	if commission >= 0.01 {
		err = p.updateRecipientWallet(p.BlockData.UserId, currencyId, commission, "node_commission", p.BlockData.BlockId, "", "encrypted", true)
		if err != nil {
			return p.ErrInfo(err)
		}
	}

	// отмечаем данную транзакцию в буфере как отработанную и ставим в очередь на удаление
	err = p.ExecSql("UPDATE wallets_buffer SET del_block_id = ? WHERE hex(hash) = ?", p.BlockData.BlockId, p.TxHash)
	if err != nil {
		return p.ErrInfo(err)
	}

	return nil
}
Example #27
0
func (t *TcpServer) Type2() {
	// размер данных
	buf := make([]byte, 4)
	_, err := t.Conn.Read(buf)
	if err != nil {
		log.Error("%v", utils.ErrInfo(err))
		return
	}
	size := utils.BinToDec(buf)
	log.Debug("size: %d", size)
	if size < 10485760 {
		// сами данные
		binaryData := make([]byte, size)
		//binaryData, err = ioutil.ReadAll(t.Conn)
		_, err = io.ReadFull(t.Conn, binaryData)
		if err != nil {
			log.Error("%v", utils.ErrInfo(err))
			return
		}
		/*
		 * Прием тр-ий от простых юзеров, а не нодов. Вызывается демоном disseminator
		 * */
		_, _, decryptedBinData, err := t.DecryptData(&binaryData)
		if err != nil {
			log.Error("%v", utils.ErrInfo(err))
			return
		}
		log.Debug("decryptedBinData: %x", decryptedBinData)
		// проверим размер
		if int64(len(binaryData)) > t.variables.Int64["max_tx_size"] {
			log.Debug("%v", utils.ErrInfo("len(txBinData) > max_tx_size"))
			return
		}
		if len(binaryData) < 5 {
			log.Debug("%v", utils.ErrInfo("len(binaryData) < 5"))
			return
		}
		decryptedBinDataFull := decryptedBinData
		txType := utils.BytesShift(&decryptedBinData, 1) // type
		txTime := utils.BytesShift(&decryptedBinData, 4) // time
		log.Debug("txType: %d", utils.BinToDec(txType))
		log.Debug("txTime: %d", utils.BinToDec(txTime))
		size := utils.DecodeLength(&decryptedBinData)
		log.Debug("size: %d", size)
		if int64(len(decryptedBinData)) < size {
			log.Debug("%v", utils.ErrInfo("len(binaryData) < size"))
			return
		}
		userId := utils.BytesToInt64(utils.BytesShift(&decryptedBinData, size))
		log.Debug("userId: %d", userId)
		highRate := 0
		if userId == 1 {
			highRate = 1
		}
		// заливаем тр-ию в БД
		err = t.ExecSql(`DELETE FROM queue_tx WHERE hex(hash) = ?`, utils.Md5(decryptedBinDataFull))
		if err != nil {
			log.Error("%v", utils.ErrInfo(err))
			return
		}
		log.Debug("INSERT INTO queue_tx (hash, high_rate, data) (%s, %d, %s)", utils.Md5(decryptedBinDataFull), highRate, utils.BinToHex(decryptedBinDataFull))
		err = t.ExecSql(`INSERT INTO queue_tx (hash, high_rate, data) VALUES ([hex], ?, [hex])`, utils.Md5(decryptedBinDataFull), highRate, utils.BinToHex(decryptedBinDataFull))
		if err != nil {
			log.Error("%v", utils.ErrInfo(err))
			return
		}
	}
}
Example #28
0
func (p *Parser) NewMiner() error {
	tcpHost := ""
	if p.BlockData != nil && p.BlockData.BlockId < 250900 {
		re := regexp.MustCompile(`^https?:\/\/([0-9a-z\_\.\-:]+)\/`)
		match := re.FindStringSubmatch(p.TxMaps.String["http_host"])
		if len(match) != 0 {
			tcpHost = match[1] + ":8088"
		}
	} else {
		tcpHost = p.TxMaps.String["tcp_host"]
	}
	// получим массив майнеров, которые должны скопировать к себе 2 фото лица юзера
	maxMinerId, err := p.DCDB.Single("SELECT max(miner_id) FROM miners").Int64()
	if err != nil {
		return p.ErrInfo(err)
	}
	// т.к. у юзера это может быть не первая попытка стать майнером, то отменяем голосования по всем предыдущим
	err = p.DCDB.ExecSql("UPDATE votes_miners SET votes_end = 1, end_block_id = ? WHERE user_id = ? AND type = 'node_voting' AND end_block_id = 0 AND votes_end = 0", p.BlockData.BlockId, p.TxUserID)
	if err != nil {
		return p.ErrInfo(err)
	}
	// создаем новое голосование для нодов
	err = p.DCDB.ExecSql("INSERT INTO votes_miners (type,	user_id,	votes_start_time) VALUES ('node_voting', ?, ?)", p.TxUserID, p.BlockData.Time)
	if err != nil {
		return p.ErrInfo(err)
	}

	// переведем все координаты в отрезки.
	var faceCoords [][2]int
	err = json.Unmarshal(p.TxMap["face_coords"], &faceCoords)
	if err != nil {
		return p.ErrInfo(err)
	}
	faceCoords = append([][2]int{{0, 0}}, faceCoords...)

	// получим отрезки
	data, err := p.DCDB.OneRow("SELECT segments, version FROM spots_compatibility").String()
	if err != nil {
		return p.ErrInfo(err)
	}
	spotsVersion := data["version"]

	var segments map[string]map[string][]string
	err = json.Unmarshal([]byte(data["segments"]), &segments)
	if err != nil {
		return p.ErrInfo(err)
	}
	n := len(segments["face"]) + 1
	faceRelations := make([]float64, n, n)
	faceRelations[0] = utils.PpLenght(faceCoords[1], faceCoords[2])

	for num, spots := range segments["face"] {
		// 1. ширина головы
		// 2. глаз-нос
		// 3. нос-губа
		// 4. губа-подбородок
		// 5. ширина челюсти
		faceRelations[utils.StrToInt(num)] = utils.Round((utils.PpLenght(faceCoords[utils.StrToInt(spots[0])], faceCoords[utils.StrToInt(spots[1])]) / faceRelations[0]), 4)
	}
	faceRelations[0] = 1

	// переведем все координаты в отрезки.
	var profileCoords [][2]int
	err = json.Unmarshal(p.TxMap["profile_coords"], &profileCoords)
	if err != nil {
		return p.ErrInfo(err)
	}
	profileCoords = append([][2]int{{0, 0}}, profileCoords...)

	n = len(segments["profile"]) + 1
	profileRelations := make([]float64, n, n)
	profileRelations[0] = utils.PpLenght(profileCoords[1], profileCoords[2])

	for num, spots := range segments["profile"] {
		// 1. край уха - край носа
		// 2. глаз - край носа
		// 3. подбородок - низ уха
		// 4. верх уха - низ уха
		profileRelations[utils.StrToInt(num)] = utils.Round((utils.PpLenght(profileCoords[utils.StrToInt(spots[0])], profileCoords[utils.StrToInt(spots[1])]) / profileRelations[0]), 4)
	}
	profileRelations[0] = 1

	addSql := make(map[string]string)
	addSql["names"] = ""
	addSql["values"] = ""
	addSql["upd"] = ""
	for j := 1; j < len(faceRelations); j++ {
		addSql["names"] += fmt.Sprintf("f%v,\n", j)
		addSql["values"] += fmt.Sprintf("'%v',\n", faceRelations[j])
		addSql["upd"] += fmt.Sprintf("f%v='%v',\n", j, faceRelations[j])
	}
	for j := 1; j < len(profileRelations); j++ {
		addSql["names"] += fmt.Sprintf("p%v,\n", j)
		addSql["values"] += fmt.Sprintf("'%v',\n", profileRelations[j])
		addSql["upd"] += fmt.Sprintf("p%v='%v',\n", j, profileRelations[j])
	}
	addSql["names"] = addSql["names"][0 : len(addSql["names"])-2]
	addSql["values"] = addSql["values"][0 : len(addSql["values"])-2]
	addSql["upd"] = addSql["upd"][0 : len(addSql["upd"])-2]

	// Для откатов
	// проверим, есть ли в БД запись, которую нужно залогировать
	logData, err := p.DCDB.OneRow("SELECT * FROM faces WHERE user_id = ?", p.TxUserID).String()
	if err != nil {
		return p.ErrInfo(err)
	}
	if len(logData) > 0 {
		addSql1 := ""
		addSql2 := ""
		for i := 1; i <= 20; i++ {
			addSql1 += fmt.Sprintf("f%v, ", i)
			addSql2 += fmt.Sprintf("%v,", logData[fmt.Sprintf("f%v", i)])
		}
		for i := 1; i <= 20; i++ {
			addSql1 += fmt.Sprintf("p%v, ", i)
			addSql2 += fmt.Sprintf("%v,", logData[fmt.Sprintf("p%v", i)])
		}
		// для откатов
		logId, err := p.ExecSqlGetLastInsertId(`
			INSERT INTO log_faces (
					user_id,
					version,
					status,
					race,
					country,
					`+addSql1+`
					prev_log_id,
					block_id
				) VALUES (
					`+logData["user_id"]+`,
					`+logData["version"]+`,
					'`+logData["status"]+`',
					`+logData["race"]+`,
					`+logData["country"]+`,
					`+addSql2+`
					`+logData["log_id"]+`,
					`+utils.Int64ToStr(p.BlockData.BlockId)+`
				)`, "log_id")
		if err != nil {
			return p.ErrInfo(err)
		}
		err = p.ExecSql("UPDATE faces SET "+addSql["upd"]+", version = ?, race = ?, country = ?, log_id = ? WHERE user_id = ?", spotsVersion, p.TxMaps.Int64["race"], p.TxMaps.Int64["country"], logId, p.TxUserID)
		if err != nil {
			return p.ErrInfo(err)
		}
	} else {
		// это первая запись в таблицу, и лог писать не с чего
		err = p.ExecSql(`
					INSERT INTO faces (
						user_id,
						version,
						race,
						country,
						` + addSql["names"] + `
					) VALUES (
						` + string(p.TxMap["user_id"]) + `,
						'` + spotsVersion + `',
						` + string(p.TxMap["race"]) + `,
						` + string(p.TxMap["country"]) + `,
						` + addSql["values"] + `
					)`)
		if err != nil {
			return p.ErrInfo(err)
		}
	}

	// проверим, есть ли в БД запись, которую надо залогировать
	logData, err = p.OneRow("SELECT * FROM miners_data WHERE user_id = ?", p.TxUserID).String()
	if err != nil {
		return p.ErrInfo(err)
	}
	if len(logData) > 0 {
		logData["node_public_key"] = string(utils.BinToHex([]byte(logData["node_public_key"])))
		// для откатов
		logId, err := p.ExecSqlGetLastInsertId(`
				INSERT INTO log_miners_data (
					user_id,
					miner_id,
					status,
					node_public_key,
					face_hash,
					profile_hash,
					photo_block_id,
					photo_max_miner_id,
					miners_keepers,
					face_coords,
					profile_coords,
					video_type,
					video_url_id,
					http_host,
					tcp_host,
					latitude,
					longitude,
					country,
					block_id,
					prev_log_id
				) VALUES (
					?, ?, ?, [hex], ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
				) `, "log_id", logData["user_id"], logData["miner_id"], logData["status"], logData["node_public_key"], logData["face_hash"], logData["profile_hash"], logData["photo_block_id"], logData["photo_max_miner_id"], logData["miners_keepers"], logData["face_coords"], logData["profile_coords"], logData["video_type"], logData["video_url_id"], logData["http_host"], logData["tcp_host"], logData["latitude"], logData["longitude"], logData["country"], p.BlockData.BlockId, logData["log_id"])
		if err != nil {
			return p.ErrInfo(err)
		}
		// обновляем таблу
		err = p.ExecSql(`
				UPDATE miners_data
				SET
					node_public_key = [hex],
					face_hash = ?,
					profile_hash = ?,
					photo_block_id = ?,
					photo_max_miner_id = ?,
					miners_keepers = ?,
					face_coords = ?,
					profile_coords = ?,
					video_type = ?,
					video_url_id = ?,
					latitude = ?,
					longitude = ?,
					country = ?,
					http_host = ?,
					tcp_host = ?,
					log_id = ?
				WHERE user_id = ?`, p.TxMap["node_public_key"], p.TxMaps.String["face_hash"], p.TxMaps.String["profile_hash"], p.BlockData.BlockId, maxMinerId, p.Variables.Int64["miners_keepers"], p.TxMaps.String["face_coords"], p.TxMaps.String["profile_coords"], p.TxMaps.String["video_type"], p.TxMaps.String["video_url_id"], p.TxMaps.Float64["latitude"], p.TxMaps.Float64["longitude"], p.TxMaps.Int64["country"], p.TxMaps.String["http_host"], tcpHost, logId, p.TxUserID)
		if err != nil {
			return p.ErrInfo(err)
		}
	} else {
		err = p.ExecSql(`
				INSERT INTO miners_data (
					user_id,
					node_public_key,
					face_hash,
					profile_hash,
					photo_block_id,
					photo_max_miner_id,
					miners_keepers,
					face_coords,
					profile_coords,
					video_type,
					video_url_id,
					latitude,
					longitude,
					country,
					http_host,
					tcp_host
			) VALUES (?, [hex], ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
			p.TxUserID, p.TxMap["node_public_key"], p.TxMaps.String["face_hash"], p.TxMaps.String["profile_hash"], p.BlockData.BlockId, maxMinerId, p.Variables.Int64["miners_keepers"], p.TxMaps.String["face_coords"], p.TxMaps.String["profile_coords"], p.TxMaps.String["video_type"], p.TxMaps.String["video_url_id"], p.TxMaps.Float64["latitude"], p.TxMaps.Float64["longitude"], p.TxMaps.Int64["country"], p.TxMaps.String["http_host"], tcpHost)
		if err != nil {
			return p.ErrInfo(err)
		}
	}
	// проверим, не наш ли это user_id
	myUserId, myBlockId, myPrefix, _, err := p.GetMyUserId(p.TxUserID)
	if err != nil {
		return err
	}
	if p.TxUserID == myUserId && myBlockId <= p.BlockData.BlockId {
		err = p.DCDB.ExecSql("UPDATE "+myPrefix+"my_node_keys SET block_id = ? WHERE hex(public_key) = ?", p.BlockData.BlockId, p.TxMap["node_public_key"])
		if err != nil {
			return p.ErrInfo(err)
		}
	}
	return nil
}
Example #29
0
/*
 * просто шлем всем, кто есть в nodes_connection хэши блока и тр-ий
 * если мы не майнер, то шлем всю тр-ию целиком, блоки слать не можем
 * если майнер - то шлем только хэши, т.к. у нас есть хост, откуда всё можно скачать
 * */
func Disseminator(chBreaker chan bool, chAnswer chan string) {
	defer func() {
		if r := recover(); r != nil {
			log.Error("daemon Recovered", r)
			panic(r)
		}
	}()

	const GoroutineName = "Disseminator"
	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 = 300
	} else {
		d.sleepTime = 1
	}
	if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) {
		return
	}
	d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName)
	if d.DCDB == nil {
		return
	}

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

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

		var hosts []map[string]string
		var nodeData map[string]string
		nodeConfig, err := d.GetNodeConfig()
		if len(nodeConfig["local_gate_ip"]) == 0 {
			// обычный режим
			hosts, err = d.GetAll(`
					SELECT miners_data.user_id, miners_data.tcp_host as host, node_public_key
					FROM nodes_connection
					LEFT JOIN miners_data ON nodes_connection.user_id = miners_data.user_id
					`, -1)
			if err != nil {
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue
			}
			if len(hosts) == 0 {
				if d.dSleep(d.sleepTime) {
					break BEGIN
				}
				log.Debug("len(hosts) == 0")
				continue
			}
		} else {
			// защищенный режим
			nodeData, err = d.OneRow("SELECT node_public_key, tcp_host FROM miners_data WHERE user_id  =  ?", nodeConfig["static_node_user_id"]).String()
			if err != nil {
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue
			}
			hosts = append(hosts, map[string]string{"host": nodeConfig["local_gate_ip"], "node_public_key": nodeData["node_public_key"], "user_id": nodeConfig["static_node_user_id"]})
		}

		myUsersIds, err := d.GetMyUsersIds(false, false)
		if err != nil {
			if d.dPrintSleep(err, d.sleepTime) {
				break BEGIN
			}
			continue
		}
		myMinersIds, err := d.GetMyMinersIds(myUsersIds)
		if err != nil {
			if d.dPrintSleep(err, d.sleepTime) {
				break BEGIN
			}
			continue
		}
		log.Debug("%v", myUsersIds)
		log.Debug("%v", myMinersIds)

		// если среди тр-ий есть смена нодовского ключа, то слать через отправку хэшей с последющей отдачей данных может не получиться
		// т.к. при некорректном нодовском ключе придет зашифрованый запрос на отдачу данных, а мы его не сможем расшифровать т.к. ключ у нас неверный
		var changeNodeKey int64
		if len(myUsersIds) > 0 {
			changeNodeKey, err = d.Single(`
				SELECT count(*)
				FROM transactions
				WHERE type = ? AND
							 user_id IN (`+strings.Join(utils.SliceInt64ToString(myUsersIds), ",")+`)
				`, utils.TypeInt("ChangeNodeKey")).Int64()
			if err != nil {
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
		}

		var dataType int64 // это тип для того, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные

		// если я майнер и работаю в обычном режиме, то должен слать хэши
		if len(myMinersIds) > 0 && len(nodeConfig["local_gate_ip"]) == 0 && changeNodeKey == 0 {

			log.Debug("0")

			dataType = 1

			// определим, от кого будем слать
			r := utils.RandInt(0, len(myMinersIds))
			myMinerId := myMinersIds[r]
			myUserId, err := d.Single("SELECT user_id FROM miners_data WHERE miner_id  =  ?", myMinerId).Int64()
			if err != nil {
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}

			// возьмем хэш текущего блока и номер блока
			// для теста ролбеков отключим на время
			data, err := d.OneRow("SELECT block_id, hash, head_hash FROM info_block WHERE sent  =  0").Bytes()
			if err != nil {
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			err = d.ExecSql("UPDATE info_block SET sent = 1")
			if err != nil {
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}

			/*
			 * Составляем данные на отправку
			 * */
			// 5 байт = наш user_id. Но они будут не первые, т.к. m_curl допишет вперед user_id получателя (нужно для пулов)
			toBeSent := utils.DecToBin(myUserId, 5)
			if len(data) > 0 { // блок
				// если 5-й байт = 0, то на приемнике будем читать блок, если = 1 , то сразу хэши тр-ий
				toBeSent = append(toBeSent, utils.DecToBin(0, 1)...)
				toBeSent = append(toBeSent, utils.DecToBin(utils.BytesToInt64(data["block_id"]), 3)...)
				toBeSent = append(toBeSent, data["hash"]...)
				toBeSent = append(toBeSent, data["head_hash"]...)
				err = d.ExecSql("UPDATE info_block SET sent = 1")
				if err != nil {
					if d.dPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
			} else { // тр-ии без блока
				toBeSent = append(toBeSent, utils.DecToBin(1, 1)...)
			}

			// возьмем хэши тр-ий
			//utils.WriteSelectiveLog("SELECT hash, high_rate FROM transactions WHERE sent = 0 AND for_self_use = 0")
			transactions, err := d.GetAll("SELECT hash, high_rate FROM transactions WHERE sent = 0 AND for_self_use = 0", -1)
			if err != nil {
				utils.WriteSelectiveLog(err)
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			// нет ни транзакций, ни блока для отправки...
			if len(transactions) == 0 && len(toBeSent) < 10 {
				//utils.WriteSelectiveLog("len(transactions) == 0")
				//log.Debug("len(transactions) == 0")
				if d.dSleep(d.sleepTime) {
					break BEGIN
				}
				log.Debug("len(transactions) == 0 && len(toBeSent) == 0")
				continue BEGIN
			}
			for _, data := range transactions {
				hexHash := utils.BinToHex([]byte(data["hash"]))
				toBeSent = append(toBeSent, utils.DecToBin(utils.StrToInt64(data["high_rate"]), 1)...)
				toBeSent = append(toBeSent, []byte(data["hash"])...)
				utils.WriteSelectiveLog("UPDATE transactions SET sent = 1 WHERE hex(hash) = " + string(hexHash))
				affect, err := d.ExecSqlGetAffect("UPDATE transactions SET sent = 1 WHERE hex(hash) = ?", hexHash)
				if err != nil {
					utils.WriteSelectiveLog(err)
					if d.dPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect))
			}

			// отправляем блок и хэши тр-ий, если есть что отправлять
			if len(toBeSent) > 0 {
				for _, host := range hosts {
					go d.DisseminatorType1(host["host"], utils.StrToInt64(host["user_id"]), host["node_public_key"], toBeSent, dataType)
				}
			}
		} else {

			log.Debug("1")

			var remoteNodeHost string
			// если просто юзер или работаю в защищенном режиме, то шлю тр-ии целиком. слать блоки не имею права.
			if len(nodeConfig["local_gate_ip"]) > 0 {
				dataType = 3
				remoteNodeHost = nodeData["host"]
			} else {
				dataType = 2
				remoteNodeHost = ""
			}

			log.Debug("dataType: %d", dataType)

			var toBeSent []byte // сюда пишем все тр-ии, которые будем слать другим нодам
			// возьмем хэши и сами тр-ии
			utils.WriteSelectiveLog("SELECT hash, data FROM transactions WHERE sent  =  0")
			rows, err := d.Query("SELECT hash, data FROM transactions WHERE sent  =  0")
			if err != nil {
				utils.WriteSelectiveLog(err)
				if d.dPrintSleep(err, d.sleepTime) {
					break BEGIN
				}
				continue BEGIN
			}
			for rows.Next() {
				var hash, data []byte
				err = rows.Scan(&hash, &data)
				if err != nil {
					rows.Close()
					if d.dPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				log.Debug("hash %x", hash)
				hashHex := utils.BinToHex(hash)
				utils.WriteSelectiveLog("UPDATE transactions SET sent = 1 WHERE hex(hash) = " + string(hashHex))
				affect, err := d.ExecSqlGetAffect("UPDATE transactions SET sent = 1 WHERE hex(hash) = ?", hashHex)
				if err != nil {
					utils.WriteSelectiveLog(err)
					rows.Close()
					if d.dPrintSleep(err, d.sleepTime) {
						break BEGIN
					}
					continue BEGIN
				}
				utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect))
				toBeSent = append(toBeSent, data...)
			}
			rows.Close()

			// шлем тр-ии
			if len(toBeSent) > 0 {
				for _, host := range hosts {

					userId := utils.StrToInt64(host["user_id"])
					go func(host string, userId int64, node_public_key string) {

						log.Debug("host %v / userId %v", host, userId)

						conn, err := utils.TcpConn(host)
						if err != nil {
							log.Error("%v", utils.ErrInfo(err))
							return
						}
						defer conn.Close()

						randTestblockHash, err := d.Single("SELECT head_hash FROM queue_testblock").String()
						if err != nil {
							log.Error("%v", utils.ErrInfo(err))
							return
						}
						// получаем IV + ключ + зашифрованный текст
						encryptedData, _, _, err := utils.EncryptData(toBeSent, []byte(node_public_key), randTestblockHash)
						if err != nil {
							log.Error("%v", utils.ErrInfo(err))
							return
						}

						// вначале шлем тип данных, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные
						_, err = conn.Write(utils.DecToBin(dataType, 1))
						if err != nil {
							log.Error("%v", utils.ErrInfo(err))
							return
						}

						// т.к. на приеме может быть пул, то нужно дописать в начало user_id, чьим нодовским ключем шифруем
						/*_, err = conn.Write(utils.DecToBin(userId, 5))
						if err != nil {
							log.Error("%v", utils.ErrInfo(err))
							return
						}*/
						encryptedData = append(utils.DecToBin(userId, 5), encryptedData...)

						// это может быть защищенное локальное соедниение (dataType = 3) и принимающему ноду нужно знать, куда дальше слать данные и чьим они зашифрованы ключем
						if len(remoteNodeHost) > 0 {
							/*
								_, err = conn.Write([]byte(remoteNodeHost))
								if err != nil {
									log.Error("%v", utils.ErrInfo(err))
									return
								}*/
							encryptedData = append([]byte(remoteNodeHost), encryptedData...)
						}

						log.Debug("encryptedData %x", encryptedData)

						// в 4-х байтах пишем размер данных, которые пошлем далее
						size := utils.DecToBin(len(encryptedData), 4)
						_, err = conn.Write(size)
						if err != nil {
							log.Error("%v", utils.ErrInfo(err))
							return
						}
						// далее шлем сами данные
						_, err = conn.Write(encryptedData)
						if err != nil {
							log.Error("%v", utils.ErrInfo(err))
							return
						}

					}(host["host"], userId, host["node_public_key"])
				}
			}
		}

		d.dbUnlock()

		if d.dSleep(d.sleepTime) {
			break BEGIN
		}
	}
	log.Debug("break BEGIN %v", GoroutineName)
}
Example #30
0
func (d *daemon) DisseminatorType1(host string, userId int64, node_public_key string, toBeSent []byte, dataType int64) {

	log.Debug("host %v / userId %v", host, userId)

	// шлем данные указанному хосту
	conn, err := utils.TcpConn(host)
	if err != nil {
		log.Error("%v", utils.ErrInfo(err))
		return
	}
	defer conn.Close()

	randTestblockHash, err := d.Single("SELECT head_hash FROM queue_testblock").String()
	if err != nil {
		log.Error("%v", utils.ErrInfo(err))
		return
	}
	// получаем IV + ключ + зашифрованный текст
	dataToBeSent, key, iv, err := utils.EncryptData(toBeSent, []byte(node_public_key), randTestblockHash)
	log.Debug("key: %s", key)
	log.Debug("iv: %s", iv)
	if err != nil {
		log.Error("%v", utils.ErrInfo(err))
		return
	}

	// вначале шлем тип данных, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные
	n, err := conn.Write(utils.DecToBin(dataType, 1))
	if err != nil {
		log.Error("%v", utils.ErrInfo(err))
		return
	}
	log.Debug("n: %x", n)

	// т.к. на приеме может быть пул, то нужно дописать в начало user_id, чьим нодовским ключем шифруем
	dataToBeSent = append(utils.DecToBin(userId, 5), dataToBeSent...)
	log.Debug("dataToBeSent: %x", dataToBeSent)

	// в 4-х байтах пишем размер данных, которые пошлем далее
	size := utils.DecToBin(len(dataToBeSent), 4)
	n, err = conn.Write(size)
	if err != nil {
		log.Error("%v", utils.ErrInfo(err))
		return
	}
	log.Debug("n: %x", n)
	n, err = conn.Write(dataToBeSent)
	if err != nil {
		log.Error("%v", utils.ErrInfo(err))
		return
	}
	log.Debug("n: %d / size: %v / len: %d", n, utils.BinToDec(size), len(dataToBeSent))

	// в ответ получаем размер данных, которые нам хочет передать сервер
	buf := make([]byte, 4)
	n, err = conn.Read(buf)
	if err != nil {
		log.Error("%v", utils.ErrInfo(err))
		return
	}
	log.Debug("n: %x", n)
	dataSize := utils.BinToDec(buf)
	log.Debug("dataSize %d", dataSize)
	// и если данных менее 1мб, то получаем их
	if dataSize < 1048576 {
		encBinaryTxHashes := make([]byte, dataSize)
		_, err = io.ReadFull(conn, encBinaryTxHashes)
		if err != nil {
			log.Error("%v", utils.ErrInfo(err))
			return
		}
		// разбираем полученные данные
		binaryTxHashes, err := utils.DecryptCFB(iv, encBinaryTxHashes, key)
		if err != nil {
			log.Error("%v", utils.ErrInfo(err))
			return
		}
		log.Debug("binaryTxHashes %x", binaryTxHashes)
		var binaryTx []byte
		for {
			// Разбираем список транзакций
			txHash := make([]byte, 16)
			if len(binaryTxHashes) >= 16 {
				txHash = utils.BytesShift(&binaryTxHashes, 16)
			}
			txHash = utils.BinToHex(txHash)
			log.Debug("txHash %s", txHash)
			utils.WriteSelectiveLog("SELECT data FROM transactions WHERE hex(hash) = " + string(txHash))
			tx, err := d.Single("SELECT data FROM transactions WHERE hex(hash) = ?", txHash).Bytes()
			log.Debug("tx %x", tx)
			if err != nil {
				utils.WriteSelectiveLog(err)
				log.Error("%v", utils.ErrInfo(err))
				return
			}
			utils.WriteSelectiveLog("tx: " + string(utils.BinToHex(tx)))
			if len(tx) > 0 {
				binaryTx = append(binaryTx, utils.EncodeLengthPlusData(tx)...)
			}
			if len(binaryTxHashes) == 0 {
				break
			}
		}

		log.Debug("binaryTx %x", binaryTx)
		// шифруем тр-ии. Вначале encData добавляется IV
		encData, _, err := utils.EncryptCFB(binaryTx, key, iv)
		if err != nil {
			log.Error("%v", utils.ErrInfo(err))
			return
		}
		log.Debug("encData %x", encData)

		// шлем серверу
		// в первых 4-х байтах пишем размер данных, которые пошлем далее
		size := utils.DecToBin(len(encData), 4)
		_, err = conn.Write(size)
		if err != nil {
			log.Error("%v", utils.ErrInfo(err))
			return
		}
		// далее шлем сами данные
		_, err = conn.Write(encData)
		if err != nil {
			log.Error("%v", utils.ErrInfo(err))
			return
		}
	}
}