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 }
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 }
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 }
func (p *Parser) NewMaxOtherCurrencies() error { currencyList := make(map[string]int64) err := json.Unmarshal(p.TxMap["new_max_other_currencies"], ¤cyList) if err != nil { return p.ErrInfo(err) } var currencyIds []int for k := range currencyList { currencyIds = append(currencyIds, utils.StrToInt(k)) } sort.Ints(currencyIds) //sort.Sort(sort.Reverse(sort.IntSlice(keys))) for _, currencyId := range currencyIds { count := currencyList[utils.IntToStr(currencyId)] logData, err := p.OneRow("SELECT max_other_currencies, log_id FROM currency WHERE id = ?", currencyId).String() if err != nil { return p.ErrInfo(err) } logId, err := p.ExecSqlGetLastInsertId("INSERT INTO log_currency ( max_other_currencies, prev_log_id ) VALUES ( ?, ? )", "log_id", logData["max_other_currencies"], logData["log_id"]) if err != nil { return p.ErrInfo(err) } err = p.ExecSql("UPDATE currency SET max_other_currencies = ?, log_id = ? WHERE id = ?", count, logId, currencyId) if err != nil { return p.ErrInfo(err) } } err = p.ExecSql("INSERT INTO max_other_currencies_time ( time ) VALUES ( ? )", p.BlockData.Time) if err != nil { return p.ErrInfo(err) } return nil }
func (p *Parser) MoneyBackRequestRollback() error { 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("DELETE FROM "+myPrefix+"my_comments WHERE type = 'seller' AND id = ?", p.TxMaps.Int64["order_id"]) 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("DELETE FROM "+myPrefix+"my_comments WHERE type = 'arbitrator' AND id = ?", p.TxMaps.Int64["order_id"]) if err != nil { return p.ErrInfo(err) } } } err = p.selectiveRollback([]string{"status"}, "orders", "id="+utils.Int64ToStr(p.TxMaps.Int64["order_id"]), false) return nil }
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 }
func IndexCf(w http.ResponseWriter, r *http.Request) { nav := "" if len(r.URL.RawQuery) > 0 { re, _ := regexp.Compile(`category\-([0-9]+)`) match := re.FindStringSubmatch(r.URL.RawQuery) if len(match) > 0 { nav = "dc_navigate ('cfCatalog', {'category_id':" + match[1] + "})\n" } else { re, _ := regexp.Compile(`([A-Z0-9]{7}|id-[0-9]+)\-?([0-9]+)?\-?(funders|comments|news|home|payment)?`) match0 := re.FindStringSubmatch(r.URL.RawQuery) if len(match0) > 1 { // $m[1] - название валюты или id валюты // $m[2] - id языка // $m[3] - тип страницы (funders|comments|news) addNav := "" re, _ := regexp.Compile(`id\-([0-9]+)`) match := re.FindStringSubmatch(match0[1]) if len(match) > 1 { addNav += "'onlyProjectId':'" + match[1] + "'," } else { addNav += "'onlyCfCurrencyName':'" + match[1] + "'," } if len(match0) > 2 { addNav += "'lang_id':'" + match0[2] + "'," } if len(match0) > 3 { addNav += "'page':'" + match0[3] + "'," } addNav = addNav[:len(addNav)-1] nav = "dc_navigate ('cfPagePreview', {" + addNav + "})\n" } } } else { nav = "dc_navigate ('cfCatalog')\n" } log.Debug(nav) c := new(Controller) c.r = r dbInit := false if len(configIni["db_user"]) > 0 || (configIni["db_type"] == "sqlite") { dbInit = true } if dbInit { var err error c.DCDB = utils.DB if c.DCDB.DB == nil { log.Error("utils.DB == nil") dbInit = false } // отсутвие таблы выдаст ошибку, значит процесс инсталяции еще не пройден и надо выдать 0-й шаг _, err = c.DCDB.Single("SELECT progress FROM install").String() if err != nil { log.Error("%v", err) dbInit = false } cfUrl, err := c.GetCfUrl() cfLang, err := c.GetAllCfLng() r.ParseForm() c.Parameters, err = c.GetParameters() log.Debug("parameters=", c.Parameters) lang := GetLang(w, r, c.Parameters) analyticsDisabled, err := utils.DB.Single(`SELECT analytics_disabled FROM config`).String() if err != nil { log.Error("%v", err) } data, err := static.Asset("static/templates/index_cf.html") t := template.New("template") t, err = t.Parse(string(data)) if err != nil { log.Error("%v", err) } b := new(bytes.Buffer) t.Execute(b, &indexCf{CfUrl: cfUrl, Lang: utils.IntToStr(lang), Nav: template.JS(nav), CfLang: cfLang, AnalyticsDisabled: analyticsDisabled}) w.Write(b.Bytes()) } }
func (p *Parser) VotesComplexRollback() error { currencyVotes := make(map[string][]float64) if p.BlockData.BlockId > 77951 { vComplex, err := makeVcomplex(p.TxMap["json_data"]) if err != nil { return p.ErrInfo(err) } if p.BlockData.BlockId > 153750 && vComplex.Admin != 0 { err := p.selectiveRollback([]string{"admin_user_id", "time"}, "votes_admin", "user_id="+string(p.TxMap["user_id"]), false) if err != nil { return p.ErrInfo(err) } } // голоса за реф. % err = p.selectiveRollback([]string{"first", "second", "third"}, "votes_referral", "user_id="+string(p.TxMap["user_id"]), false) if err != nil { return p.ErrInfo(err) } currencyVotes = vComplex.Currency } else { // раньше не было рефских и выбора админа vComplex := make(map[string][]float64) err := json.Unmarshal(p.TxMap["json_data"], &vComplex) if err != nil { return p.ErrInfo(err) } currencyVotes = vComplex } // сортируем по $currency_id в обратном порядке var currencyIds []int for k := range currencyVotes { currencyIds = append(currencyIds, utils.StrToInt(k)) } sort.Sort(sort.Reverse(sort.IntSlice(currencyIds))) for _, currencyId := range currencyIds { currencyIdStr := utils.IntToStr(currencyId) // miner_pct err := p.selectiveRollback([]string{"pct", "time"}, "votes_miner_pct", "user_id="+string(p.TxMap["user_id"])+" AND currency_id = "+currencyIdStr, false) if err != nil { return p.ErrInfo(err) } // user_pct err = p.selectiveRollback([]string{"pct"}, "votes_user_pct", "user_id="+string(p.TxMap["user_id"])+" AND currency_id = "+currencyIdStr, false) if err != nil { return p.ErrInfo(err) } // reduction err = p.selectiveRollback([]string{"pct", "time"}, "votes_reduction", "user_id="+string(p.TxMap["user_id"])+" AND currency_id = "+currencyIdStr, false) if err != nil { return p.ErrInfo(err) } // max_promised_amount err = p.selectiveRollback([]string{"amount"}, "votes_max_promised_amount", "user_id="+string(p.TxMap["user_id"])+" AND currency_id = "+currencyIdStr, false) if err != nil { return p.ErrInfo(err) } // max_other_currencies err = p.selectiveRollback([]string{"count"}, "votes_max_other_currencies", "user_id="+string(p.TxMap["user_id"])+" AND currency_id = "+currencyIdStr, false) if err != nil { return p.ErrInfo(err) } // проверим, не наш ли это user_id myUserId, _, myPrefix, _, err := p.GetMyUserId(p.TxUserID) if err != nil { return p.ErrInfo(err) } if p.TxUserID == myUserId { // отметимся, что голосовали, чтобы не пришло уведомление о необходимости голосовать раз в 2 недели err = p.ExecSql("DELETE FROM "+myPrefix+"my_complex_votes WHERE last_voting =?", p.BlockData.Time) if err != nil { return p.ErrInfo(err) } } } return nil }
func (c *Controller) PoolDataBaseDump() (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() dumpUserId := utils.StrToInt64(c.r.FormValue("dump_user_id")) mainMap := make(map[string][]map[string]string) if dumpUserId > 0 { for _, table := range consts.MyTables { data, err := c.GetAll(`SELECT * FROM `+table, -1) if err != nil { return "", utils.ErrInfo(err) } mainMap[table] = data } } else { for i := 0; i < len(c.CommunityUsers); i++ { for _, table := range consts.MyTables { table = utils.Int64ToStr(c.CommunityUsers[i]) + "_" + table if utils.InSliceString(table, allTables) { data, err := c.GetAll(`SELECT * FROM `+table, -1) for k, arr := range data { for name, value := range arr { if ok, _ := regexp.MatchString("(hash_code|public_key|encrypted)", name); ok { data[k][name] = string(utils.BinToHex([]byte(value))) } } } if err != nil { return "", utils.ErrInfo(err) } 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_users_backup-`+t.Format(c.TimeFormat)+`.txt`) if _, err := c.w.Write(jsonData); err != nil { return "", utils.ErrInfo(errors.New("unable to write text")) } err = json.Unmarshal(jsonData, &mainMap) if err != nil { return "", utils.ErrInfo(err) } // для теста for table, arr := range mainMap { log.Debug(table) for i, data := range arr { log.Debug("%v", i) colNames := "" values := []string{} qq := "" for name, value := range data { colNames += name + "," values = append(values, value) if ok, _ := regexp.MatchString("(hash_code|public_key|encrypted)", name); ok { qq += "[hex]," } else { qq += "?," } } colNames = colNames[0 : len(colNames)-1] qq = qq[0 : len(qq)-1] query := `INSERT INTO ` + table + ` (` + colNames + `) VALUES (` + qq + `)` log.Debug("%v", query) log.Debug("%v", values) } } return "", nil }
func (c *Controller) Assignments() (string, error) { var randArr []int64 // Нельзя завершить голосование юзеров раньше чем через сутки, даже если набрано нужное кол-во голосов. // В голосовании нодов ждать сутки не требуется, т.к. там нельзя поставить поддельных нодов // Модерация новых майнеров // берем тех, кто прошел проверку нодов (type='node_voting') num, err := c.Single("SELECT count(id) FROM votes_miners WHERE votes_end = 0 AND type = 'user_voting'").Int64() if err != nil { return "", utils.ErrInfo(err) } if num > 0 { randArr = append(randArr, 1) } // Модерация promised_amount // вначале получим ID валют, которые мы можем проверять. currency, err := c.GetList("SELECT currency_id FROM promised_amount WHERE status IN ('mining', 'repaid') AND user_id = ?", c.SessUserId).String() if err != nil { return "", utils.ErrInfo(err) } addSql := "" currencyIds := strings.Join(currency, ",") if len(currencyIds) > 0 || c.SessUserId == 1 { if c.SessUserId != 1 { addSql = "AND currency_id IN (" + currencyIds + ")" } num, err := c.Single("SELECT count(id) FROM promised_amount WHERE status = 'pending' AND del_block_id = 0 " + addSql + "").Int64() if err != nil { return "", utils.ErrInfo(err) } if num > 0 { randArr = append(randArr, 2) } } log.Debug("randArr %v", randArr) var AssignType int64 if len(randArr) > 0 { AssignType = randArr[utils.RandInt(0, len(randArr))] } cloneHosts := make(map[int64][]string) var photoHosts []string examplePoints := make(map[string]string) tplName := "assignments" tplTitle := "assignments" var txType string var txTypeId int64 var timeNow int64 var myRace, myCountry, mainQuestion, newPromiseAmount, videoHost string var promisedAmountData, userInfo map[string]string switch AssignType { case 1: // *********************************** // задания по модерации новых майнеров // *********************************** txType = "VotesMiner" txTypeId = utils.TypeInt(txType) timeNow = utils.Time() userInfo, err = c.OneRow(` SELECT miners_data.user_id, votes_miners.id as vote_id, face_coords, profile_coords, video_type, video_url_id, photo_block_id, photo_max_miner_id, miners_keepers, http_host FROM votes_miners LEFT JOIN miners_data ON miners_data.user_id = votes_miners.user_id LEFT JOIN `+c.MyPrefix+`my_tasks ON `+c.MyPrefix+`my_tasks.id = votes_miners.id WHERE votes_end = 0 AND votes_miners.type = 'user_voting' AND (`+c.MyPrefix+`my_tasks.time IS NULL OR (`+c.MyPrefix+`my_tasks.time < ? AND `+c.MyPrefix+`my_tasks.type = 'miner')) `, utils.Time()-consts.ASSIGN_TIME).String() if err != nil { return "", utils.ErrInfo(err) } if len(userInfo) == 0 { tplName = "assignments" break } examplePoints, err = c.GetPoints(c.Lang) if err != nil { return "", utils.ErrInfo(err) } // получим ID майнеров, у которых лежат фото нужного нам юзера minersIds := utils.GetMinersKeepers(userInfo["photo_block_id"], userInfo["photo_max_miner_id"], userInfo["miners_keepers"], true) if len(minersIds) > 0 { photoHosts, err = c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } } // отрезки майнера, которого проверяем relations, err := c.OneRow("SELECT * FROM faces WHERE user_id = ?", userInfo["user_id"]).String() if err != nil { return "", utils.ErrInfo(err) } // получим допустимые расхождения между точками и совместимость версий data_, err := c.OneRow("SELECT tolerances, compatibility FROM spots_compatibility").String() if err != nil { return "", utils.ErrInfo(err) } tolerances := make(map[string]map[string]string) if err := json.Unmarshal([]byte(data_["tolerances"]), &tolerances); err != nil { return "", utils.ErrInfo(err) } var compatibility []int if err := json.Unmarshal([]byte(data_["compatibility"]), &compatibility); err != nil { return "", utils.ErrInfo(err) } // формируем кусок SQL-запроса для соотношений отрезков addSqlTolerances := "" typesArr := []string{"face", "profile"} for i := 0; i < len(typesArr); i++ { for j := 1; j <= len(tolerances[typesArr[i]]); j++ { currentRelations := utils.StrToFloat64(relations[typesArr[i][:1]+utils.IntToStr(j)]) diff := utils.StrToFloat64(tolerances[typesArr[i]][utils.IntToStr(j)]) * currentRelations if diff == 0 { continue } min := currentRelations - diff max := currentRelations + diff addSqlTolerances += typesArr[i][:1] + utils.IntToStr(j) + ">" + utils.Float64ToStr(min) + " AND " + typesArr[i][:1] + utils.IntToStr(j) + " < " + utils.Float64ToStr(max) + " AND " } } addSqlTolerances = addSqlTolerances[:len(addSqlTolerances)-4] // формируем кусок SQL-запроса для совместимости версий addSqlCompatibility := "" for i := 0; i < len(compatibility); i++ { addSqlCompatibility += fmt.Sprintf(`%d,`, compatibility[i]) } addSqlCompatibility = addSqlCompatibility[:len(addSqlCompatibility)-1] // получаем из БД похожие фото rows, err := c.Query(c.FormatQuery(` SELECT miners_data.user_id, photo_block_id, photo_max_miner_id, miners_keepers FROM faces LEFT JOIN miners_data ON miners_data.user_id = faces.user_id WHERE `+addSqlTolerances+` AND version IN (`+addSqlCompatibility+`) AND faces.status = 'used' AND miners_data.user_id != ? LIMIT 100 `), userInfo["user_id"]) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() for rows.Next() { var photo_block_id, photo_max_miner_id, miners_keepers string var user_id int64 err = rows.Scan(&user_id, &photo_block_id, &photo_max_miner_id, &miners_keepers) if err != nil { return "", utils.ErrInfo(err) } // майнеры, у которых можно получить фото нужного нам юзера minersIds := utils.GetMinersKeepers(photo_block_id, photo_max_miner_id, miners_keepers, true) if len(minersIds) > 0 { photoHosts, err = c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } } cloneHosts[user_id] = photoHosts } data, err := c.OneRow("SELECT race, country FROM " + c.MyPrefix + "my_table").Int64() myRace = c.Races[data["race"]] myCountry = consts.Countries[int(data["country"])] tplName = "assignments_new_miner" tplTitle = "assignmentsNewMiner" case 2: promisedAmountData, err = c.OneRow(` SELECT id, currency_id, amount, user_id, video_type, video_url_id FROM promised_amount WHERE status = 'pending' AND del_block_id = 0 ` + addSql + ` `).String() if err != nil { return "", utils.ErrInfo(err) } promisedAmountData["currency_name"] = c.CurrencyList[utils.StrToInt64(promisedAmountData["currency_id"])] // проверим, не голосовали ли мы за это в последние 30 минут repeated, err := c.Single("SELECT id FROM "+c.MyPrefix+"my_tasks WHERE type = 'promised_amount' AND id = ? AND time > ?", promisedAmountData["id"], utils.Time()-consts.ASSIGN_TIME).Int64() if err != nil { return "", utils.ErrInfo(err) } if repeated > 0 { tplName = "assignments" tplTitle = "assignments" break } // если нету видео на ютубе, то получаем host юзера, где брать видео if promisedAmountData["video_url_id"] == "null" { videoHost, err = c.Single("SELECT http_host FROM miners_data WHERE user_id = ?", promisedAmountData["user_id"]).String() if err != nil { return "", utils.ErrInfo(err) } } // каждый раз обязательно проверяем, где находится юзер userInfo, err = c.OneRow(` SELECT latitude, user_id, longitude, photo_block_id, photo_max_miner_id, miners_keepers, http_host FROM miners_data WHERE user_id = ? `, promisedAmountData["user_id"]).String() if err != nil { return "", utils.ErrInfo(err) } // получим ID майнеров, у которых лежат фото нужного нам юзера minersIds := utils.GetMinersKeepers(userInfo["photo_block_id"], userInfo["photo_max_miner_id"], userInfo["miners_keepers"], true) if len(minersIds) > 0 { photoHosts, err = c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } } txType = "VotesPromisedAmount" txTypeId = utils.TypeInt(txType) timeNow = utils.Time() newPromiseAmount = strings.Replace(c.Lang["new_promise_amount"], "[amount]", promisedAmountData["amount"], -1) newPromiseAmount = strings.Replace(newPromiseAmount, "[currency]", promisedAmountData["currency_name"], -1) mainQuestion = strings.Replace(c.Lang["main_question"], "[amount]", promisedAmountData["amount"], -1) mainQuestion = strings.Replace(mainQuestion, "[currency]", promisedAmountData["currency_name"], -1) tplName = "assignments_promised_amount" tplTitle = "assignmentsPromisedAmount" default: tplName = "assignments" tplTitle = "assignments" } TemplateStr, err := makeTemplate(tplName, tplTitle, &AssignmentsPage{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, UserId: c.SessUserId, TimeNow: timeNow, TxType: txType, TxTypeId: txTypeId, SignData: "", CurrencyList: c.CurrencyList, MainQuestion: mainQuestion, NewPromiseAmount: newPromiseAmount, MyRace: myRace, MyCountry: myCountry, ExamplePoints: examplePoints, VideoHost: videoHost, PhotoHosts: photoHosts, PromisedAmountData: promisedAmountData, UserInfo: userInfo, CloneHosts: cloneHosts}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (p *Parser) SendDcRollback() error { // нужно отметить в log_time_money_orders, что тр-ия НЕ прошла в блок err := p.ExecSql("UPDATE log_time_money_orders SET del_block_id = 0 WHERE hex(tx_hash) = ?", p.TxHash) if err != nil { return p.ErrInfo(err) } // 6 комиссия нода-генератора блока if p.TxMaps.Float64["commission"] >= 0.01 { err = p.generalRollback("wallets", p.BlockData.UserId, "AND currency_id = "+utils.Int64ToStr(p.TxMaps.Int64["currency_id"]), false) if err != nil { return p.ErrInfo(err) } // возможно были списания по кредиту нода-генератора err = p.loanPaymentsRollback(p.BlockData.UserId, p.TxMaps.Int64["currency_id"]) if err != nil { return p.ErrInfo(err) } } // 5 обновим сумму на кошельке получателю // возможно были списания по кредиту err = p.loanPaymentsRollback(p.TxMaps.Int64["to_user_id"], p.TxMaps.Int64["currency_id"]) if err != nil { return p.ErrInfo(err) } err = p.generalRollback("wallets", p.TxMaps.Int64["to_user_id"], "AND currency_id = "+utils.Int64ToStr(p.TxMaps.Int64["currency_id"]), false) if err != nil { return p.ErrInfo(err) } // 4 обновим сумму на кошельке отправителя err = p.generalRollback("wallets", p.TxMaps.Int64["from_user_id"], "AND currency_id = "+utils.Int64ToStr(p.TxMaps.Int64["currency_id"]), false) if err != nil { return p.ErrInfo(err) } // 3 err = p.pointsUpdateRollbackMain(p.TxMaps.Int64["to_user_id"]) if err != nil { return p.ErrInfo(err) } // 2 err = p.pointsUpdateRollbackMain(p.TxMaps.Int64["from_user_id"]) if err != nil { return p.ErrInfo(err) } // 1 err = p.pointsUpdateRollbackMain(p.BlockData.UserId) if err != nil { return p.ErrInfo(err) } // отменяем чистку буфера err = p.ExecSql("UPDATE wallets_buffer SET del_block_id = 0 WHERE hex(hash) = ?", p.TxHash) if err != nil { return p.ErrInfo(err) } if p.BlockData.BlockId > consts.ARBITRATION_BLOCK_START { // на какой период манибека согласен продавец 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 { delOrder := false 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 { err = p.generalRollback("wallets", p.TxMaps.Int64["arbitrator"+iStr], "AND currency_id = "+utils.Int64ToStr(p.TxMaps.Int64["currency_id"]), false) if err != nil { return p.ErrInfo(err) } if !delOrder { err = p.ExecSql("DELETE FROM orders WHERE block_id = ? AND buyer = ? AND seller = ? AND currency_id = ? AND amount = ?", p.BlockData.BlockId, p.TxMaps.Int64["from_user_id"], p.TxMaps.Int64["to_user_id"], p.TxMaps.Int64["currency_id"], p.TxMaps.Float64["amount"]) if err != nil { return p.ErrInfo(err) } err = p.rollbackAI("orders", 1) if err != nil { return p.ErrInfo(err) } delOrder = true } // возможно были списания по кредиту арбитра err = p.loanPaymentsRollback(p.TxMaps.Int64["arbitrator"+iStr], p.TxMaps.Int64["currency_id"]) if err != nil { return p.ErrInfo(err) } } } } } err = p.mydctxRollback() if err != nil { return p.ErrInfo(err) } return nil }
/** Обработка данных (блоков или транзакций), пришедших с гейта. Только проверка. */ func (p *Parser) ParseDataGate(onlyTx bool) error { var err error p.dataPre() p.TxIds = []string{} p.Variables, err = p.GetAllVariables() if err != nil { return utils.ErrInfo(err) } transactionBinaryData := p.BinaryData var transactionBinaryDataFull []byte // если это транзакции (type>0), а не блок (type==0) if p.dataType > 0 { // проверим, есть ли такой тип тр-ий if len(consts.TxTypes[p.dataType]) == 0 { return p.ErrInfo("Incorrect tx type " + utils.IntToStr(p.dataType)) } log.Debug("p.dataType %v", p.dataType) transactionBinaryData = append(utils.DecToBin(int64(p.dataType), 1), transactionBinaryData...) transactionBinaryDataFull = transactionBinaryData // нет ли хэша этой тр-ии у нас в БД? err = p.CheckLogTx(transactionBinaryDataFull) if err != nil { return p.ErrInfo(err) } p.TxHash = utils.Md5(transactionBinaryData) // преобразуем бинарные данные транзакции в массив p.TxSlice, err = p.ParseTransaction(&transactionBinaryData) if err != nil { return p.ErrInfo(err) } log.Debug("p.TxSlice", p.TxSlice) if len(p.TxSlice) < 3 { return p.ErrInfo(errors.New("len(p.TxSlice) < 3")) } // время транзакции может быть немного больше, чем время на ноде. // у нода может быть просто не настроено время. // время транзакции используется только для борьбы с атаками вчерашними транзакциями. // А т.к. мы храним хэши в log_transaction за 36 часов, то боятся нечего. curTime := utils.Time() if utils.BytesToInt64(p.TxSlice[2])-consts.MAX_TX_FORW > curTime || utils.BytesToInt64(p.TxSlice[2]) < curTime-consts.MAX_TX_BACK { return p.ErrInfo(errors.New("incorrect tx time")) } // $this->transaction_array[3] могут подсунуть пустой if !utils.CheckInputData(p.TxSlice[3], "bigint") { return p.ErrInfo(errors.New("incorrect user id")) } } // если это блок if p.dataType == 0 { txCounter := make(map[int64]int64) // если есть $only_tx=true, то значит идет восстановление уже проверенного блока и заголовок не требуется if !onlyTx { err = p.ParseBlock() if err != nil { return p.ErrInfo(err) } // проверим данные, указанные в заголовке блока err = p.CheckBlockHeader() if err != nil { return p.ErrInfo(err) } } log.Debug("onlyTx", onlyTx) // если в ходе проверки тр-ий возникает ошибка, то вызываем откатчик всех занесенных тр-ий. Эта переменная для него p.fullTxBinaryData = p.BinaryData var txForRollbackTo []byte if len(p.BinaryData) > 0 { for { transactionSize := utils.DecodeLength(&p.BinaryData) if len(p.BinaryData) == 0 { return utils.ErrInfo(fmt.Errorf("empty BinaryData")) } // отчекрыжим одну транзакцию от списка транзакций transactionBinaryData := utils.BytesShift(&p.BinaryData, transactionSize) transactionBinaryDataFull = transactionBinaryData // добавляем взятую тр-ию в набор тр-ий для RollbackTo, в котором пойдем в обратном порядке txForRollbackTo = append(txForRollbackTo, utils.EncodeLengthPlusData(transactionBinaryData)...) // нет ли хэша этой тр-ии у нас в БД? err = p.CheckLogTx(transactionBinaryDataFull) if err != nil { p.RollbackTo(txForRollbackTo, true, false) return p.ErrInfo(err) } p.TxHash = utils.Md5(transactionBinaryData) p.TxSlice, err = p.ParseTransaction(&transactionBinaryData) log.Debug("p.TxSlice %s", p.TxSlice) if err != nil { p.RollbackTo(txForRollbackTo, true, false) return p.ErrInfo(err) } var userId int64 // txSlice[3] могут подсунуть пустой if len(p.TxSlice) > 3 { if !utils.CheckInputData(p.TxSlice[3], "int64") { return utils.ErrInfo(fmt.Errorf("empty user_id")) } else { userId = utils.BytesToInt64(p.TxSlice[3]) } } else { return utils.ErrInfo(fmt.Errorf("empty user_id")) } // считаем по каждому юзеру, сколько в блоке от него транзакций txCounter[userId]++ // чтобы 1 юзер не смог прислать дос-блок размером в 10гб, который заполнит своими же транзакциями if txCounter[userId] > p.Variables.Int64["max_block_user_transactions"] { p.RollbackTo(txForRollbackTo, true, false) return utils.ErrInfo(fmt.Errorf("max_block_user_transactions")) } // проверим, есть ли такой тип тр-ий _, ok := consts.TxTypes[utils.BytesToInt(p.TxSlice[1])] if !ok { return utils.ErrInfo(fmt.Errorf("nonexistent type")) } p.TxMap = map[string][]byte{} // для статы p.TxIds = append(p.TxIds, string(p.TxSlice[1])) MethodName := consts.TxTypes[utils.BytesToInt(p.TxSlice[1])] log.Debug("MethodName", MethodName+"Init") err_ := utils.CallMethod(p, MethodName+"Init") if _, ok := err_.(error); ok { log.Debug("error: %v", err) p.RollbackTo(txForRollbackTo, true, true) return utils.ErrInfo(err_.(error)) } log.Debug("MethodName", MethodName+"Front") err_ = utils.CallMethod(p, MethodName+"Front") if _, ok := err_.(error); ok { log.Debug("error: %v", err) p.RollbackTo(txForRollbackTo, true, true) return utils.ErrInfo(err_.(error)) } // пишем хэш тр-ии в лог err = p.InsertInLogTx(transactionBinaryDataFull, utils.BytesToInt64(p.TxMap["time"])) if err != nil { return utils.ErrInfo(err) } if len(p.BinaryData) == 0 { break } } } } else { // Оперативные транзакции MethodName := consts.TxTypes[p.dataType] log.Debug("MethodName", MethodName+"Init") err_ := utils.CallMethod(p, MethodName+"Init") if _, ok := err_.(error); ok { return utils.ErrInfo(err_.(error)) } log.Debug("MethodName", MethodName+"Front") err_ = utils.CallMethod(p, MethodName+"Front") if _, ok := err_.(error); ok { return utils.ErrInfo(err_.(error)) } // пишем хэш тр-ии в лог err = p.InsertInLogTx(transactionBinaryDataFull, utils.BytesToInt64(p.TxMap["time"])) if err != nil { return utils.ErrInfo(err) } } return nil }
func Start(dir string, thrustWindowLoder *window.Window) { var err error IosLog("start") defer func() { if r := recover(); r != nil { log.Error("Recovered", r) panic(r) } }() if dir != "" { fmt.Println("dir", dir) *utils.Dir = dir } IosLog("dir:" + dir) fmt.Println("utils.Dir", *utils.Dir) fmt.Println("dcVersion:", consts.VERSION) log.Debug("dcVersion: %v", consts.VERSION) // читаем config.ini configIni := make(map[string]string) configIni_, err := config.NewConfig("ini", *utils.Dir+"/config.ini") if err != nil { IosLog("err:" + fmt.Sprintf("%s", utils.ErrInfo(err))) log.Error("%v", utils.ErrInfo(err)) } else { configIni, err = configIni_.GetSection("default") } // убьем ранее запущенный Dcoin if !utils.Mobile() { fmt.Println("kill dcoin.pid") if _, err := os.Stat(*utils.Dir + "/dcoin.pid"); err == nil { dat, err := ioutil.ReadFile(*utils.Dir + "/dcoin.pid") if err != nil { log.Error("%v", utils.ErrInfo(err)) } var pidMap map[string]string err = json.Unmarshal(dat, &pidMap) if err != nil { log.Error("%v", utils.ErrInfo(err)) } fmt.Println("old PID ("+*utils.Dir+"/dcoin.pid"+"):", pidMap["pid"]) utils.DB, err = utils.NewDbConnect(configIni) err = KillPid(pidMap["pid"]) if nil != err { fmt.Println(err) log.Error("KillPid %v", utils.ErrInfo(err)) } if fmt.Sprintf("%s", err) != "null" { fmt.Println(fmt.Sprintf("%s", err)) // даем 15 сек, чтобы завершиться предыдущему процессу for i := 0; i < 15; i++ { log.Debug("waiting killer %d", i) if _, err := os.Stat(*utils.Dir + "/dcoin.pid"); err == nil { fmt.Println("waiting killer") utils.Sleep(1) } else { // если dcoin.pid нет, значит завершился break } } } } } // сохраним текущий pid и версию if !utils.Mobile() { pid := os.Getpid() PidAndVer, err := json.Marshal(map[string]string{"pid": utils.IntToStr(pid), "version": consts.VERSION}) if err != nil { log.Error("%v", utils.ErrInfo(err)) } err = ioutil.WriteFile(*utils.Dir+"/dcoin.pid", PidAndVer, 0644) if err != nil { log.Error("%v", utils.ErrInfo(err)) panic(err) } } controllers.SessInit() controllers.ConfigInit() daemons.ConfigInit() go func() { utils.DB, err = utils.NewDbConnect(configIni) log.Debug("%v", utils.DB) IosLog("utils.DB:" + fmt.Sprintf("%v", utils.DB)) if err != nil { IosLog("err:" + fmt.Sprintf("%s", utils.ErrInfo(err))) log.Error("%v", utils.ErrInfo(err)) panic(err) os.Exit(1) } }() f, err := os.OpenFile(*utils.Dir+"/dclog.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0777) if err != nil { IosLog("err:" + fmt.Sprintf("%s", utils.ErrInfo(err))) log.Error("%v", utils.ErrInfo(err)) panic(err) os.Exit(1) } defer f.Close() IosLog("configIni:" + fmt.Sprintf("%v", configIni)) var backend *logging.LogBackend switch configIni["log_output"] { case "file": backend = logging.NewLogBackend(f, "", 0) case "console": backend = logging.NewLogBackend(os.Stderr, "", 0) case "file_console": //backend = logging.NewLogBackend(io.MultiWriter(f, os.Stderr), "", 0) default: backend = logging.NewLogBackend(f, "", 0) } backendFormatter := logging.NewBackendFormatter(backend, format) backendLeveled := logging.AddModuleLevel(backendFormatter) logLevel_ := "DEBUG" if *utils.LogLevel == "" { logLevel_ = configIni["log_level"] } else { logLevel_ = *utils.LogLevel } logLevel, err := logging.LogLevel(logLevel_) if err != nil { log.Error("%v", utils.ErrInfo(err)) } log.Debug("logLevel: %v", logLevel) backendLeveled.SetLevel(logLevel, "") logging.SetBackend(backendLeveled) rand.Seed(time.Now().UTC().UnixNano()) // если есть OldFileName, значит работаем под именем tmp_dc и нужно перезапуститься под нормальным именем log.Error("OldFileName %v", *utils.OldFileName) if *utils.OldFileName != "" { // вначале нужно обновить БД в зависимости от версии dat, err := ioutil.ReadFile(*utils.Dir + "/dcoin.pid") if err != nil { log.Error("%v", utils.ErrInfo(err)) } var pidMap map[string]string err = json.Unmarshal(dat, &pidMap) if err != nil { log.Error("%v", utils.ErrInfo(err)) } log.Debug("OldFileName %v", *utils.OldFileName) err = utils.CopyFileContents(*utils.Dir+`/dc.tmp`, *utils.OldFileName) if err != nil { log.Debug("%v", os.Stderr) log.Debug("%v", utils.ErrInfo(err)) } // ждем подключения к БД for { if utils.DB == nil || utils.DB.DB == nil { utils.Sleep(1) continue } break } if len(pidMap["version"]) > 0 { if utils.VersionOrdinal(pidMap["version"]) < utils.VersionOrdinal("1.0.2b5") { log.Debug("%v", "ALTER TABLE config ADD COLUMN analytics_disabled smallint") err = utils.DB.ExecSql(`ALTER TABLE config ADD COLUMN analytics_disabled smallint`) if err != nil { log.Error("%v", utils.ErrInfo(err)) } } if utils.VersionOrdinal(pidMap["version"]) < utils.VersionOrdinal("2.0.1b2") { log.Debug("%v", "ALTER TABLE config ADD COLUMN sqlite_db_url varchar(255)") err = utils.DB.ExecSql(`ALTER TABLE config ADD COLUMN sqlite_db_url varchar(255)`) if err != nil { log.Error("%v", utils.ErrInfo(err)) } } } err = utils.DB.Close() if err != nil { log.Error("%v", utils.ErrInfo(err)) } fmt.Println("DB Closed") err = os.Remove(*utils.Dir + "/dcoin.pid") if err != nil { log.Error("%v", utils.ErrInfo(err)) } log.Debug("dc.tmp %v", *utils.Dir+`/dc.tmp`) err = exec.Command(*utils.OldFileName, "-dir", *utils.Dir).Start() if err != nil { log.Debug("%v", os.Stderr) log.Debug("%v", utils.ErrInfo(err)) } log.Debug("OldFileName %v", *utils.OldFileName) os.Exit(1) } // откат БД до указанного блока if *utils.RollbackToBlockId > 0 { utils.DB, err = utils.NewDbConnect(configIni) parser := new(dcparser.Parser) parser.DCDB = utils.DB err = parser.RollbackToBlockId(*utils.RollbackToBlockId) if err != nil { fmt.Println(err) panic(err) } fmt.Print("complete") os.Exit(0) } log.Debug("public") IosLog("public") if _, err := os.Stat(*utils.Dir + "/public"); os.IsNotExist(err) { err = os.Mkdir(*utils.Dir+"/public", 0755) if err != nil { log.Error("%v", utils.ErrInfo(err)) panic(err) os.Exit(1) } } log.Debug("daemonsStart") IosLog("daemonsStart") daemons.StartDaemons() IosLog("MonitorDaemons") // мониторинг демонов daemonsTable := make(map[string]string) go func() { for { daemonNameAndTime := <-daemons.MonitorDaemonCh daemonsTable[daemonNameAndTime[0]] = daemonNameAndTime[1] if utils.Time()%10 == 0 { log.Debug("daemonsTable: %v\n", daemonsTable) } } }() // сигналы демонам для выхода IosLog("signals") stopdaemons.Signals() utils.Sleep(1) // мониторим сигнал из БД о том, что демонам надо завершаться go stopdaemons.WaitStopTime() BrowserHttpHost := "http://localhost:8089" HandleHttpHost := "" ListenHttpHost := ":" + *utils.ListenHttpHost go func() { // уже прошли процесс инсталяции, где юзер указал БД и был перезапуск кошелька if len(configIni["db_type"]) > 0 && !utils.Mobile() { for { // ждем, пока произойдет подключение к БД в другой гоурутине if utils.DB == nil || utils.DB.DB == nil { utils.Sleep(1) fmt.Println("wait DB") } else { break } } fmt.Println("GET http host") BrowserHttpHost, HandleHttpHost, ListenHttpHost = GetHttpHost() // для биржы нужен хост или каталог, поэтому нужно подключение к БД exhangeHttpListener(HandleHttpHost) // для ноды тоже нужна БД tcpListener() } IosLog(fmt.Sprintf("BrowserHttpHost: %v, HandleHttpHost: %v, ListenHttpHost: %v", BrowserHttpHost, HandleHttpHost, ListenHttpHost)) fmt.Printf("BrowserHttpHost: %v, HandleHttpHost: %v, ListenHttpHost: %v\n", BrowserHttpHost, HandleHttpHost, ListenHttpHost) // включаем листинг веб-сервером для клиентской части http.HandleFunc(HandleHttpHost+"/", controllers.Index) http.HandleFunc(HandleHttpHost+"/content", controllers.Content) http.HandleFunc(HandleHttpHost+"/ajax", controllers.Ajax) http.HandleFunc(HandleHttpHost+"/tools", controllers.Tools) http.HandleFunc(HandleHttpHost+"/cf/", controllers.IndexCf) http.HandleFunc(HandleHttpHost+"/cf/content", controllers.ContentCf) http.Handle(HandleHttpHost+"/public/", noDirListing(http.FileServer(http.Dir(*utils.Dir)))) http.Handle(HandleHttpHost+"/static/", http.FileServer(&assetfs.AssetFS{Asset: static.Asset, AssetDir: static.AssetDir, Prefix: ""})) log.Debug("ListenHttpHost", ListenHttpHost) IosLog(fmt.Sprintf("ListenHttpHost: %v", ListenHttpHost)) fmt.Println("ListenHttpHost", ListenHttpHost) httpListener(ListenHttpHost, BrowserHttpHost) if *utils.Console == 0 && !utils.Mobile() { utils.Sleep(1) if thrustWindowLoder != nil { thrustWindowLoder.Close() thrustWindow := thrust.NewWindow(thrust.WindowOptions{ RootUrl: BrowserHttpHost, Size: commands.SizeHW{Width: 1024, Height: 600}, }) thrustWindow.HandleEvent("*", func(cr commands.EventResult) { fmt.Println("HandleEvent", cr) }) thrustWindow.HandleRemote(func(er commands.EventResult, this *window.Window) { fmt.Println("RemoteMessage Recieved:", er.Message.Payload) openBrowser(er.Message.Payload) // Keep in mind once we have the message, lets say its json of some new type we made, // We can unmarshal it to that type. // Same goes for the other way around. this.SendRemoteMessage("boop") }) thrustWindow.Show() thrustWindow.Focus() } else { openBrowser(BrowserHttpHost) } } }() // ожидает появления свежих записей в чате, затем ждет появления коннектов // (заносятся из демеона connections и от тех, кто сам подключился к ноде) go utils.ChatOutput(utils.ChatNewTx) log.Debug("ALL RIGHT") IosLog("ALL RIGHT") fmt.Println("ALL RIGHT") utils.Sleep(3600 * 24 * 90) log.Debug("EXIT") }
func (c *Controller) EncryptComment() (string, error) { var err error c.r.ParseForm() txType := c.r.FormValue("type") var toId int64 var toIds []int64 toIds_ := c.r.FormValue("to_ids") if len(toIds_) == 0 { toId = utils.StrToInt64(c.r.FormValue("to_id")) } else { var toIdsMap map[string]string err = json.Unmarshal([]byte(toIds_), &toIdsMap) if err != nil { return "", utils.ErrInfo(err) } for _, uid := range toIdsMap { if utils.StrToInt64(uid) > 0 { toIds = append(toIds, utils.StrToInt64(uid)) } } } comment := c.r.FormValue("comment") if len(comment) > 1024 { return "", errors.New("incorrect comment") } var toUserId int64 if txType == "project" { toUserId, err = c.Single("SELECT user_id FROM cf_projects WHERE id = ?", toId).Int64() if err != nil { return "", utils.ErrInfo(err) } } else { toUserId = toId } if len(toIds) == 0 { toIds = []int64{toUserId} } log.Debug("toId:", toId) log.Debug("toIds:", toIds) log.Debug("toUserId:", toUserId) enc := make(map[string]string) for i := 0; i < len(toIds); i++ { if toIds[i] == 0 { enc[utils.IntToStr(i)] = "0" continue } // если получатель майнер, тогда шифруем нодовским ключем minersData, err := c.OneRow("SELECT miner_id, node_public_key FROM miners_data WHERE user_id = ?", toIds[i]).String() if err != nil { return "", utils.ErrInfo(err) } var publicKey string if utils.StrToInt(minersData["miner_id"]) > 0 && txType != "cash_request" && txType != "bug_reporting" && txType != "project" && txType != "money_back" && txType != "restoringAccess" { publicKey = minersData["node_public_key"] } else { publicKey, err = c.Single("SELECT public_key_0 FROM users WHERE user_id = ?", toIds[i]).String() if err != nil { return "", utils.ErrInfo(err) } } pub, err := utils.BinToRsaPubKey([]byte(publicKey)) if err != nil { return "", utils.ErrInfo(err) } enc_, err := rsa.EncryptPKCS1v15(rand.Reader, pub, []byte(comment)) if err != nil { return "", utils.ErrInfo(err) } enc[utils.IntToStr(i)] = string(utils.BinToHex(enc_)) } if len(enc) < 5 && len(enc) > 0 { for i := len(enc); i < 5; i++ { enc[utils.IntToStr(i)] = "0" } } log.Debug("enc:", enc) if txType != "arbitration_arbitrators" { return string(enc["0"]), nil } else { result, err := json.Marshal(enc) if err != nil { return "", utils.ErrInfo(err) } return string(result), nil } }
/* * Каждые 2 недели собираем инфу о голосах за % и создаем тр-ию, которая * попадет в DC сеть только, если мы окажемся генератором блока * */ func ReductionGenerator(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "ReductionGenerator" d := new(daemon) d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } d.goRoutineName = GoroutineName d.chAnswer = chAnswer d.chBreaker = chBreaker if utils.Mobile() { d.sleepTime = 3600 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } err = d.notMinerSetSleepTime(1800) if err != nil { log.Error("%v", err) return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } blockId, err := d.GetBlockId() if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if blockId == 0 { if d.unlockPrintSleep(errors.New("blockId == 0"), d.sleepTime) { break BEGIN } continue BEGIN } _, _, myMinerId, _, _, _, err := d.TestBlock() if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // а майнер ли я ? if myMinerId == 0 { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } variables, err := d.GetAllVariables() curTime := utils.Time() var reductionType string var reductionCurrencyId int var reductionPct int64 // ===== ручное урезание денежной массы // получаем кол-во обещанных сумм у разных юзеров по каждой валюте. start_time есть только у тех, у кого статус mining/repaid promisedAmount, err := d.GetMap(` SELECT currency_id, count(user_id) as count FROM ( SELECT currency_id, user_id FROM promised_amount WHERE start_time < ? AND del_block_id = 0 AND del_mining_block_id = 0 AND status IN ('mining', 'repaid') GROUP BY user_id, currency_id ) as t1 GROUP BY currency_id`, "currency_id", "count", (curTime - variables.Int64["min_hold_time_promise_amount"])) if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Info("%v", "promisedAmount", promisedAmount) // берем все голоса юзеров rows, err := d.Query(d.FormatQuery(` SELECT currency_id, pct, count(currency_id) as votes FROM votes_reduction WHERE time > ? GROUP BY currency_id, pct `), curTime-variables.Int64["reduction_period"]) if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var votes, pct int64 var currency_id string err = rows.Scan(¤cy_id, &pct, &votes) if err != nil { rows.Close() if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(promisedAmount[currency_id]) == 0 || promisedAmount[currency_id] == "0" { continue } // если голосов за урезание > 50% от числа всех держателей данной валюты if votes >= utils.StrToInt64(promisedAmount[currency_id])/2 { // проверим, прошло ли 2 недели с последнего урезания reductionTime, err := d.Single("SELECT max(time) FROM reduction WHERE currency_id = ? AND type = 'manual'", currency_id).Int64() if err != nil { rows.Close() if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if curTime-reductionTime > variables.Int64["reduction_period"] { reductionCurrencyId = utils.StrToInt(currency_id) reductionPct = pct reductionType = "manual" log.Info("%v", "reductionCurrencyId", reductionCurrencyId, "reductionPct", reductionPct, "reductionType", reductionType) break } } } rows.Close() // ======= авто-урезание денежной массы из-за малого объема обещанных сумм // получаем кол-во DC на кошельках sumWallets_, err := d.GetMap("SELECT currency_id, sum(amount) as sum_amount FROM wallets GROUP BY currency_id", "currency_id", "sum_amount") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } sumWallets := make(map[int]float64) for currencyId, amount := range sumWallets_ { sumWallets[utils.StrToInt(currencyId)] = utils.StrToFloat64(amount) } // получаем кол-во TDC на обещанных суммах, плюсуем к тому, что на кошельках sumTdc, err := d.GetMap("SELECT currency_id, sum(tdc_amount) as sum_amount FROM promised_amount GROUP BY currency_id", "currency_id", "sum_amount") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for currencyId, amount := range sumTdc { currencyIdInt := utils.StrToInt(currencyId) if sumWallets[currencyIdInt] == 0 { sumWallets[currencyIdInt] = utils.StrToFloat64(amount) } else { sumWallets[currencyIdInt] += utils.StrToFloat64(amount) } } log.Debug("sumWallets", sumWallets) // получаем суммы обещанных сумм sumPromisedAmount, err := d.GetMap(` SELECT currency_id, sum(amount) as sum_amount FROM promised_amount WHERE status = 'mining' AND del_block_id = 0 AND del_mining_block_id = 0 AND (cash_request_out_time = 0 OR cash_request_out_time > ?) GROUP BY currency_id `, "currency_id", "sum_amount", curTime-variables.Int64["cash_request_time"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("sumPromisedAmount", sumPromisedAmount) if len(sumWallets) > 0 { for currencyId, sumAmount := range sumWallets { //недопустимо для WOC if currencyId == 1 { continue } reductionTime, err := d.Single("SELECT max(time) FROM reduction WHERE currency_id = ? AND type = 'auto'", currencyId).Int64() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("reductionTime", reductionTime) // прошло ли 48 часов if curTime-reductionTime <= consts.AUTO_REDUCTION_PERIOD { log.Debug("curTime-reductionTime <= consts.AUTO_REDUCTION_PERIOD %d <= %d", curTime-reductionTime, consts.AUTO_REDUCTION_PERIOD) continue } // если обещанных сумм менее чем 100% от объема DC на кошельках, то запускаем урезание log.Debug("utils.StrToFloat64(sumPromisedAmount[utils.IntToStr(currencyId)]) < sumAmount*consts.AUTO_REDUCTION_PROMISED_AMOUNT_PCT %d < %d", utils.StrToFloat64(sumPromisedAmount[utils.IntToStr(currencyId)]), sumAmount*consts.AUTO_REDUCTION_PROMISED_AMOUNT_PCT) if utils.StrToFloat64(sumPromisedAmount[utils.IntToStr(currencyId)]) < sumAmount*consts.AUTO_REDUCTION_PROMISED_AMOUNT_PCT { // проверим, есть ли хотя бы 1000 юзеров, у которых на кошелках есть или была данная валюты countUsers, err := d.Single("SELECT count(user_id) FROM wallets WHERE currency_id = ?", currencyId).Int64() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("countUsers>=countUsers %d >= %d", countUsers, consts.AUTO_REDUCTION_PROMISED_AMOUNT_MIN) if countUsers >= consts.AUTO_REDUCTION_PROMISED_AMOUNT_MIN { reductionCurrencyId = currencyId reductionPct = consts.AUTO_REDUCTION_PCT reductionType = "promised_amount" break } } } } if reductionCurrencyId > 0 && reductionPct > 0 { _, myUserId, _, _, _, _, err := d.TestBlock() forSign := fmt.Sprintf("%v,%v,%v,%v,%v,%v", utils.TypeInt("NewReduction"), curTime, myUserId, reductionCurrencyId, reductionPct, reductionType) log.Debug("forSign = %v", forSign) binSign, err := d.GetBinSign(forSign, myUserId) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } data := utils.DecToBin(utils.TypeInt("NewReduction"), 1) data = append(data, utils.DecToBin(curTime, 4)...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(myUserId))...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(int64(reductionCurrencyId)))...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(reductionPct))...) data = append(data, utils.EncodeLengthPlusData([]byte(reductionType))...) data = append(data, utils.EncodeLengthPlusData([]byte(binSign))...) err = d.InsertReplaceTxInQueue(data) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // и не закрывая main_lock переводим нашу тр-ию в verified=1, откатив все несовместимые тр-ии // таким образом у нас будут в блоке только актуальные голоса. // а если придет другой блок и станет verified=0, то эта тр-ия просто удалится. p := new(dcparser.Parser) p.DCDB = d.DCDB err = p.TxParser(utils.HexToBin(utils.Md5(data)), data, true) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func Shop(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "Shop" 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 = 120 } 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 } myBlockId, err := d.GetMyBlockId() blockId, err := d.GetBlockId() if myBlockId > blockId { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } currencyList, err := d.GetCurrencyList(false) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } // нужно знать текущий блок, который есть у большинства нодов blockId, err = d.GetConfirmedBlockId() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } // сколько должно быть подтверждений, т.е. кол-во блоков сверху confirmations := int64(5) // берем всех юзеров по порядку community, err := d.GetCommunityUsers() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } for _, userId := range community { privateKey := "" myPrefix := utils.Int64ToStr(userId) + "_" allTables, err := d.GetAllTables() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if !utils.InSliceString(myPrefix+"my_keys", allTables) { continue } // проверим, майнер ли minerId, err := d.GetMinerId(userId) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if minerId > 0 { // наш приватный ключ нода, которым будем расшифровывать комменты privateKey, err = d.GetNodePrivateKey(myPrefix) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } // возможно, что комменты будут зашифрованы юзерским ключем if len(privateKey) == 0 { privateKey, err = d.GetMyPrivateKey(myPrefix) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } // если это еще не майнер и админ ноды не указал его приватный ключ в табле my_keys, то $private_key будет пуст if len(privateKey) == 0 { continue } myData, err := d.OneRow("SELECT shop_secret_key, shop_callback_url FROM " + myPrefix + "my_table").String() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // Получаем инфу о входящих переводах и начисляем их на счета юзеров dq := d.GetQuotes() rows, err := d.Query(d.FormatQuery(` SELECT id, block_id, type_id, currency_id, amount, to_user_id, comment_status, comment FROM `+dq+myPrefix+`my_dc_transactions`+dq+` WHERE type = 'from_user' AND block_id < ? AND merchant_checked = 0 AND status = 'approved' ORDER BY id DESC `), blockId-confirmations) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var id, block_id, type_id, currency_id, to_user_id int64 var comment_status, comment string var amount float64 err = rows.Scan(&id, &block_id, &type_id, ¤cy_id, &amount, &to_user_id, &comment_status, &comment) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if len(myData["shop_callback_url"]) == 0 { // отметим merchant_checked=1, чтобы больше не брать эту тр-ию err = d.ExecSql("UPDATE "+myPrefix+"my_dc_transactions SET merchant_checked = 1 WHERE id = ?", id) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } continue } // вначале нужно проверить, точно ли есть такой перевод в блоке 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 } // сравнение данных из таблы my_dc_transactions с тем, что в блоке if utils.BytesToInt64(txMap["user_id"]) == userId && utils.BytesToInt64(txMap["currency_id"]) == currency_id && utils.BytesToFloat64(txMap["amount"]) == amount && string(utils.BinToHex(txMap["comment"])) == comment && utils.BytesToInt64(txMap["to_user_id"]) == to_user_id { decryptedComment := comment // расшифруем коммент if comment_status == "encrypted" { block, _ := pem.Decode([]byte(privateKey)) 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, []byte(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 } } // возможно, что чуть раньше было reduction, а это значит, что все тр-ии, // которые мы ещё не обработали и которые были До блока с reduction нужно принимать с учетом reduction // т.к. средства на нашем счете уже урезались, а вот те, что после reduction - остались в том виде, в котором пришли lastReduction, err := d.OneRow("SELECT block_id, pct FROM reduction WHERE currency_id = ? ORDER BY block_id", currency_id).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) } // делаем запрос к callback скрипту r, _ := regexp.Compile(`(?i)\s*#\s*([0-9]+)\s*`) order := r.FindStringSubmatch(decryptedComment) orderId := 0 if len(order) > 0 { orderId = utils.StrToInt(order[1]) } txId := id sign := fmt.Sprintf("%v:%v:%v:%v:%v:%v:%v:%v", amount, currencyList[currency_id], orderId, decryptedComment, txMap["user_id"], blockId, txId, myData["shop_secret_key"]) data := url.Values{} data.Add("amount", utils.Float64ToStrPct(amount)) data.Add("currency", currencyList[currency_id]) data.Add("order_id", utils.IntToStr(orderId)) data.Add("message", decryptedComment) data.Add("user_id", string(txMap["user_id"])) data.Add("block_id", string(txMap["block_id"])) data.Add("tx_id", utils.Int64ToStr(txId)) data.Add("sign", sign) client := &http.Client{} req, err := http.NewRequest("POST", myData["shop_callback_url"], bytes.NewBufferString(data.Encode())) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") req.Header.Add("Content-Length", utils.IntToStr(len(data.Encode()))) resp, err := client.Do(req) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } //contents, _ := ioutil.ReadAll(resp.Body) if resp.StatusCode == 200 { // отметим merchant_checked=1, чтобы больше не брать эту тр-ию err = d.ExecSql("UPDATE "+myPrefix+"my_dc_transactions SET merchant_checked = 1 WHERE id = ?", id) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } } } } rows.Close() } if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func (p *Parser) NewForexOrderFront() error { err := p.generalCheck() if err != nil { return p.ErrInfo(err) } verifyData := map[string]string{"sell_currency_id": "int", "sell_rate": "sell_rate", "amount": "amount", "buy_currency_id": "int", "commission": "amount"} err = p.CheckInputData(verifyData) if err != nil { return p.ErrInfo(err) } if p.TxMaps.Int64["sell_currency_id"] == p.TxMaps.Int64["buy_currency_id"] { return p.ErrInfo("sell_currency_id == buy_currency_id") } if p.TxMaps.Float64["sell_rate"] == 0 { return p.ErrInfo("sell_rate=0") } if p.TxMaps.Money["amount"] == 0 { return p.ErrInfo("amount=0") } if p.TxMaps.Money["amount"]*p.TxMaps.Float64["sell_rate"] < 0.01 { return p.ErrInfo("amount * sell_rate < 0.01") } checkCurrency, err := p.CheckCurrency(p.TxMaps.Int64["sell_currency_id"]) if err != nil || !checkCurrency { return p.ErrInfo("!sell_currency_id") } checkCurrency, err = p.CheckCurrency(p.TxMaps.Int64["buy_currency_id"]) if err != nil || !checkCurrency { return p.ErrInfo("!buy_currency_id") } p.TxMaps.Int64["currency_id"] = p.TxMaps.Int64["sell_currency_id"] nodeCommission, err := p.getMyNodeCommission(p.TxMaps.Int64["currency_id"], p.TxUserID, p.TxMaps.Money["amount"]) // проверим, удовлетворяет ли нас комиссия, которую предлагает юзер if p.TxMaps.Money["commission"] < nodeCommission { return p.ErrInfo("commission") } // есть ли нужная сумма на кошельке p.TxMaps.Int64["from_user_id"] = p.TxMaps.Int64["user_id"] for i := 0; i < 5; i++ { p.TxMaps.Float64["arbitrator"+utils.IntToStr(i)+"_commission"] = 0 } _, err = p.checkSenderMoney(p.TxMaps.Int64["currency_id"], p.TxMaps.Int64["from_user_id"], p.TxMaps.Money["amount"], p.TxMaps.Money["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) } forSign := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", p.TxMap["type"], p.TxMap["time"], p.TxMap["user_id"], p.TxMap["sell_currency_id"], p.TxMap["sell_rate"], p.TxMap["amount"], p.TxMap["buy_currency_id"], p.TxMap["commission"]) 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.checkSpamMoney(p.TxMaps.Int64["sell_currency_id"], p.TxMaps.Money["amount"]) if err != nil { return p.ErrInfo(err) } return nil }
func Connector(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() if _, err := os.Stat(*utils.Dir + "/nodes.inc"); os.IsNotExist(err) { data, err := static.Asset("static/nodes.inc") if err != nil { log.Error("%v", err) } err = ioutil.WriteFile(*utils.Dir+"/nodes.inc", []byte(data), 0644) if err != nil { log.Error("%v", err) } } GoroutineName := "Connector" 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 = 600 } else { d.sleepTime = 30 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } // соединения для чата иногда отваливаются, поэтому в цикле мониторим состояние go func() { for { if myUserIdForChat == 0 { utils.Sleep(1) continue } if len(utils.ChatOutConnections) < 5 || len(utils.ChatInConnections) < 5 { go d.chatConnector() } utils.Sleep(30) } }() BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } nodeConfig, err := d.GetNodeConfig() if len(nodeConfig["local_gate_ip"]) > 0 { utils.Sleep(2) continue } var delMiners []string var hosts []map[string]string var nodeCount int64 idArray := make(map[int]int64) nodesInc := make(map[string]string) // ровно стольким нодам мы будем слать хэши блоков и тр-ий var maxHosts = consts.OUT_CONNECTIONS if utils.StrToInt64(nodeConfig["out_connections"]) > 0 { maxHosts = utils.StrToInt(nodeConfig["out_connections"]) } log.Info("%v", maxHosts) collective, err := d.GetCommunityUsers() if err != nil { log.Error("%v", err) return } if len(collective) == 0 { myUserId, err := d.GetMyUserId("") if err != nil { log.Error("%v", err) return } collective = append(collective, myUserId) myUserIdForChat = myUserId } else { myUserIdForChat, err = d.Single(`SELECT pool_admin_user_id FROM config`).Int64() if err != nil { log.Error("%v", err) return } } // в сингл-моде будет только $my_miners_ids[0] myMinersIds, err := d.GetMyMinersIds(collective) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } log.Info("%v", myMinersIds) nodesBan, err := d.GetMap(` SELECT tcp_host, ban_start FROM nodes_ban LEFT JOIN miners_data ON miners_data.user_id = nodes_ban.user_id `, "tcp_host", "ban_start") log.Info("%v", nodesBan) nodesConnections, err := d.GetAll(` SELECT nodes_connection.host, nodes_connection.user_id, ban_start, miner_id FROM nodes_connection LEFT JOIN nodes_ban ON nodes_ban.user_id = nodes_connection.user_id LEFT JOIN miners_data ON miners_data.user_id = nodes_connection.user_id `, -1) //fmt.Println("nodesConnections", nodesConnections) log.Debug("nodesConnections: %v", nodesConnections) for _, data := range nodesConnections { // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } /*// проверим соотвествие хоста и user_id ok, err := d.Single("SELECT user_id FROM miners_data WHERE user_id = ? AND tcp_host = ?", data["user_id"], data["host"]).Int64() if err != nil { utils.Sleep(1) continue BEGIN } if ok == 0 { err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ? OR user_id = ?", data["host"], data["user_id"]) if err != nil { utils.Sleep(1) continue BEGIN } }*/ // если нода забанена недавно if utils.StrToInt64(data["ban_start"]) > utils.Time()-consts.NODE_BAN_TIME { delMiners = append(delMiners, data["miner_id"]) err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ? OR user_id = ?", data["host"], data["user_id"]) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } continue } hosts = append(hosts, map[string]string{"host": data["host"], "user_id": data["user_id"]}) nodesInc[data["host"]] = data["user_id"] nodeCount++ } log.Debug("hosts: %v", hosts) /* ch := make(chan *answerType) for _, host := range hosts { userId := utils.StrToInt64(host["user_id"]) go func(userId int64, host string) { ch_ := make(chan *answerType, 1) go func() { log.Debug("host: %v / userId: %v", host, userId) ch_ <- check(host, userId) }() select { case reachable := <-ch_: ch <- reachable case <-time.After(consts.WAIT_CONFIRMED_NODES * time.Second): ch <- &answerType{userId: userId, answer: 0} } }(userId, host["host"]) } log.Debug("%v", "hosts", hosts) var newHosts []map[string]string var countOk int // если нода не отвечает, то удалем её из таблы nodes_connection for i := 0; i < len(hosts); i++ { result := <-ch if result.answer == 0 { log.Info("delete %v", result.userId) err = d.ExecSql("DELETE FROM nodes_connection WHERE user_id = ?", result.userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } } for _, data := range hosts { if utils.StrToInt64(data["user_id"]) != result.userId { newHosts = append(newHosts, data) } } } else { countOk++ } log.Info("answer: %v", result) } */ var countOk int hosts = checkHosts(hosts, &countOk) log.Debug("countOk: %d / hosts: %v", countOk, hosts) // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } // добьем недостающие хосты до $max_hosts var newHostsForCheck []map[string]string if len(hosts) < maxHosts { need := maxHosts - len(hosts) max, err := d.Single("SELECT max(miner_id) FROM miners").Int() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } i0 := 0 for { rand := 1 if max > 1 { rand = utils.RandInt(1, max+1) } idArray[rand] = 1 i0++ if i0 > 30 || len(idArray) >= need || len(idArray) >= max { break } } log.Info("%v", "idArray", idArray) // удалим себя for _, id := range myMinersIds { delete(idArray, int(id)) } // Удалим забаннные хосты for _, id := range delMiners { delete(idArray, utils.StrToInt(id)) } log.Info("%v", "idArray", idArray) ids := "" if len(idArray) > 0 { for id, _ := range idArray { ids += utils.IntToStr(id) + "," } ids = ids[:len(ids)-1] minersHosts, err := d.GetMap(` SELECT tcp_host, user_id FROM miners_data WHERE miner_id IN (`+ids+`)`, "tcp_host", "user_id") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for host, userId := range minersHosts { if len(nodesBan[host]) > 0 { if utils.StrToInt64(nodesBan[host]) > utils.Time()-consts.NODE_BAN_TIME { continue } } //hosts = append(hosts, map[string]string{"host": host, "user_id": userId}) /*err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ?", host) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug(host)*/ newHostsForCheck = append(newHostsForCheck, map[string]string{"user_id": userId, "host": host}) /*err = d.ExecSql("INSERT INTO nodes_connection ( host, user_id ) VALUES ( ?, ? )", host, userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN }*/ } } } hosts = checkHosts(newHostsForCheck, &countOk) log.Debug("countOk: %d / hosts: %v", countOk, hosts) // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } log.Debug("%v", "hosts", hosts) // если хосты не набрались из miner_data, то берем из файла if len(hosts) < 10 { hostsData_, err := ioutil.ReadFile(*utils.Dir + "/nodes.inc") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } hostsData := strings.Split(string(hostsData_), "\n") log.Debug("%v", "hostsData_", hostsData_) log.Debug("%v", "hostsData", hostsData) max := 0 log.Debug("maxHosts: %v", maxHosts) if len(hosts) > maxHosts-1 { max = maxHosts } else { max = len(hostsData) } log.Debug("max: %v", max) for i := 0; i < max; i++ { r := utils.RandInt(0, max) if len(hostsData) <= r { continue } hostUserId := strings.Split(hostsData[r], ";") if len(hostUserId) == 1 { continue } host, userId := hostUserId[0], hostUserId[1] if utils.InSliceInt64(utils.StrToInt64(userId), collective) { continue } if len(nodesBan[host]) > 0 { if utils.StrToInt64(nodesBan[host]) > utils.Time()-consts.NODE_BAN_TIME { continue } } /* err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ?", host) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug(host) /*err = d.ExecSql("INSERT INTO nodes_connection ( host, user_id ) VALUES ( ?, ? )", host, userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN }*/ newHostsForCheck = append(newHostsForCheck, map[string]string{"user_id": userId, "host": host}) nodesInc[host] = userId } } hosts = checkHosts(newHostsForCheck, &countOk) log.Debug("countOk: %d / hosts: %v", countOk, hosts) // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } for _, host := range hosts { err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ?", host["host"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("INSERT INTO nodes_connection ( host, user_id ) VALUES ( ?, ? )", host["host"], host["user_id"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if nodeCount > 5 { nodesFile := "" for k, v := range nodesInc { nodesFile += k + ";" + v + "\n" } nodesFile = nodesFile[:len(nodesFile)-1] err := ioutil.WriteFile(*utils.Dir+"/nodes.inc", []byte(nodesFile), 0644) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } var sleepTime int if countOk < 2 { sleepTime = 5 } else { sleepTime = d.sleepTime } if d.dSleep(sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func (p *Parser) VotesComplex() error { currencyVotes := make(map[string][]float64) if p.BlockData.BlockId > 77951 { vComplex, err := makeVcomplex(p.TxMap["json_data"]) if err != nil { return p.ErrInfo(err) } currencyVotes = vComplex.Currency // голоса за реф. % p.selectiveLoggingAndUpd([]string{"first", "second", "third"}, []interface{}{vComplex.Referral["first"], vComplex.Referral["second"], vComplex.Referral["third"]}, "votes_referral", []string{"user_id"}, []string{string(p.TxMap["user_id"])}) // раньше не было выборов админа if p.BlockData.BlockId >= 153750 && vComplex.Admin > 0 { p.selectiveLoggingAndUpd([]string{"admin_user_id", "time"}, []interface{}{vComplex.Admin, p.TxTime}, "votes_admin", []string{"user_id"}, []string{string(p.TxMap["user_id"])}) } } else { // раньше не было рефских и выбора админа vComplex := make(map[string][]float64) err := json.Unmarshal(p.TxMap["json_data"], &vComplex) if err != nil { return p.ErrInfo(err) } currencyVotes = vComplex } var currencyIds []int for k := range currencyVotes { currencyIds = append(currencyIds, utils.StrToInt(k)) } sort.Ints(currencyIds) //sort.Sort(sort.Reverse(sort.IntSlice(keys))) for _, currencyId := range currencyIds { data := currencyVotes[utils.IntToStr(currencyId)] currencyIdStr := utils.IntToStr(currencyId) UserIdStr := string(p.TxMap["user_id"]) // miner_pct err := p.selectiveLoggingAndUpd([]string{"pct", "time"}, []interface{}{utils.Float64ToStr(data[0]), p.TxTime}, "votes_miner_pct", []string{"user_id", "currency_id"}, []string{UserIdStr, currencyIdStr}) if err != nil { return p.ErrInfo(err) } // user_pct err = p.selectiveLoggingAndUpd([]string{"pct"}, []interface{}{utils.Float64ToStr(data[1])}, "votes_user_pct", []string{"user_id", "currency_id"}, []string{UserIdStr, currencyIdStr}) if err != nil { return p.ErrInfo(err) } // max_promised_amount err = p.selectiveLoggingAndUpd([]string{"amount"}, []interface{}{int64(data[2])}, "votes_max_promised_amount", []string{"user_id", "currency_id"}, []string{UserIdStr, currencyIdStr}) if err != nil { return p.ErrInfo(err) } // max_other_currencies err = p.selectiveLoggingAndUpd([]string{"count"}, []interface{}{int64(data[3])}, "votes_max_other_currencies", []string{"user_id", "currency_id"}, []string{UserIdStr, currencyIdStr}) if err != nil { return p.ErrInfo(err) } // reduction err = p.selectiveLoggingAndUpd([]string{"pct", "time"}, []interface{}{int64(data[4]), p.TxTime}, "votes_reduction", []string{"user_id", "currency_id"}, []string{UserIdStr, currencyIdStr}) if err != nil { return p.ErrInfo(err) } // проверим, не наш ли это user_id myUserId, myBlockId, myPrefix, _, err := p.GetMyUserId(p.TxUserID) if err != nil { return p.ErrInfo(err) } if p.TxUserID == myUserId && myBlockId <= p.BlockData.BlockId { // отметимся, что голосовали, чтобы не пришло уведомление о необходимости голосовать раз в 2 недели // может быть дубль, поэтому ошибки не проверяем p.ExecSql("INSERT INTO "+myPrefix+"my_complex_votes ( last_voting ) VALUES ( ? )", p.BlockData.Time) } } return nil }
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 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 }
func (p *Parser) NewMinerFront() error { err := p.generalCheck() if err != nil { return p.ErrInfo(err) } // получим кол-во точек для face и profile exampleSpots_, err := p.DCDB.Single("SELECT example_spots FROM spots_compatibility").String() if err != nil { return p.ErrInfo(err) } exampleSpots := new(exampleSpots) err = json.Unmarshal([]byte(exampleSpots_), &exampleSpots) if err != nil { return p.ErrInfo(err) } if !utils.CheckInputData(p.TxMap["race"], "race") { return utils.ErrInfoFmt("race") } if !utils.CheckInputData(p.TxMap["country"], "country") { return utils.ErrInfoFmt("country") } if !utils.CheckInputData(p.TxMap["latitude"], "coordinate") { return utils.ErrInfoFmt("latitude") } if !utils.CheckInputData(p.TxMap["longitude"], "coordinate") { return utils.ErrInfoFmt("longitude") } if !utils.CheckInputData(p.TxMap["http_host"], "http_host") { return utils.ErrInfoFmt("http_host") } if p.BlockData == nil || p.BlockData.BlockId > 250900 { if !utils.CheckInputData(p.TxMap["tcp_host"], "tcp_host") { return utils.ErrInfoFmt("tcp_host") } } if !utils.CheckInputData_(p.TxMap["face_coords"], "coords", utils.IntToStr(len(exampleSpots.Face)-1)) { return utils.ErrInfoFmt("face_coords") } if !utils.CheckInputData_(p.TxMap["profile_coords"], "coords", utils.IntToStr(len(exampleSpots.Profile)-1)) { return utils.ErrInfoFmt("profile_coords") } if !utils.CheckInputData(p.TxMap["face_hash"], "photo_hash") { return utils.ErrInfoFmt("face_hash") } if !utils.CheckInputData(p.TxMap["profile_hash"], "photo_hash") { return utils.ErrInfoFmt("profile_hash") } if !utils.CheckInputData(p.TxMap["video_type"], "video_type") { return utils.ErrInfoFmt("video_type") } if !utils.CheckInputData(p.TxMap["video_url_id"], "video_url_id") { return utils.ErrInfoFmt("video_url_id %s", p.TxMap["video_url_id"]) } if !utils.CheckInputData(p.TxMap["node_public_key"], "public_key") { return utils.ErrInfoFmt("node_public_key") } forSign := "" if p.BlockData != nil && p.BlockData.BlockId < 250900 { forSign = fmt.Sprintf("%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["race"], p.TxMap["country"], p.TxMap["latitude"], p.TxMap["longitude"], p.TxMap["http_host"], p.TxMap["face_hash"], p.TxMap["profile_hash"], p.TxMap["face_coords"], p.TxMap["profile_coords"], p.TxMap["video_type"], p.TxMap["video_url_id"], p.TxMap["node_public_key"]) } else { forSign = fmt.Sprintf("%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["race"], p.TxMap["country"], p.TxMap["latitude"], p.TxMap["longitude"], p.TxMap["http_host"], p.TxMap["tcp_host"], p.TxMap["face_hash"], p.TxMap["profile_hash"], p.TxMap["face_coords"], p.TxMap["profile_coords"], p.TxMap["video_type"], p.TxMap["video_url_id"], p.TxMap["node_public_key"]) } CheckSignResult, err := utils.CheckSign(p.PublicKeys, forSign, p.TxMap["sign"], false) if err != nil { return p.ErrInfo(err) } if !CheckSignResult { return utils.ErrInfoFmt("incorrect sign") } // проверим, не кончились ли попытки стать майнером у данного юзера count, err := p.CountMinerAttempt(p.TxUserID, "user_voting") if count >= p.Variables.Int64["miner_votes_attempt"] { return utils.ErrInfoFmt("miner_votes_attempt") } if err != nil { return p.ErrInfo(err) } // на всякий случай не даем начать нодовское, если идет юзерское голосование userVoting, err := p.DCDB.Single("SELECT id FROM votes_miners WHERE user_id = ? AND type = 'user_voting' AND votes_end = 0", p.TxUserID).String() if err != nil { return p.ErrInfo(err) } if len(userVoting) > 0 { return utils.ErrInfoFmt("existing $user_voting") } // проверим, не является ли юзер майнером и не разжалованный ли это бывший майнер minerStatus, err := p.DCDB.Single("SELECT status FROM miners_data WHERE user_id = ? AND status IN ('miner','passive_miner','suspended_miner')", p.TxUserID).String() if err != nil { return p.ErrInfo(err) } if len(minerStatus) > 0 { return utils.ErrInfoFmt("incorrect miner status") } // разрешен 1 запрос за сутки err = p.limitRequest(p.Variables.Int64["limit_new_miner"], "new_miner", p.Variables.Int64["limit_new_miner_period"]) if err != nil { return p.ErrInfo(err) } return nil }
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 }
func (c *Controller) Upgrade3() (string, error) { log.Debug("Upgrade3") userProfile := *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg" userFace := *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg" if _, err := os.Stat(userProfile); os.IsNotExist(err) { userProfile = "" } else { userProfile = "public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg?r=" + utils.IntToStr(utils.RandInt(0, 99999)) } if _, err := os.Stat(userFace); os.IsNotExist(err) { userFace = "" } else { userFace = "public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg?r=" + utils.IntToStr(utils.RandInt(0, 99999)) } log.Debug("userProfile: %s", userProfile) log.Debug("userFace: %s", userFace) // текущий набор точек для шаблонов examplePoints, err := c.GetPoints(c.Lang) if err != nil { return "", utils.ErrInfo(err) } // точки, которые юзер уже отмечал data, err := c.OneRow("SELECT face_coords, profile_coords FROM " + c.MyPrefix + "my_table").String() if err != nil { return "", utils.ErrInfo(err) } faceCoords := "" profileCoords := "" if len(data["face_coords"]) > 0 { faceCoords = data["face_coords"] profileCoords = data["profile_coords"] } saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "5", -1) upgradeMenu := utils.MakeUpgradeMenu(3) TemplateStr, err := makeTemplate("upgrade_3", "upgrade3", &upgrade3Page{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, SaveAndGotoStep: saveAndGotoStep, UpgradeMenu: upgradeMenu, UserId: c.SessUserId, FaceCoords: faceCoords, ProfileCoords: profileCoords, UserProfile: userProfile, UserFace: userFace, ExamplePoints: examplePoints, IOS: utils.IOS(), Mobile: utils.Mobile()}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
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 }
func (c *Controller) DcoinKey() (string, error) { var err error c.r.ParseForm() // на IOS/Android запрос ключа идет без сессии из objective C (UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://127.0.0.1:8089/ajax?controllerName=dcoinKey&ios=1"]]];) local := false // чтобы по локалке никто не украл приватный ключ if ok, _ := regexp.MatchString(`^(\:\:)|(127\.0\.0\.1)(:[0-9]+)?$`, c.r.RemoteAddr); ok { local = true } if utils.Mobile() && c.SessUserId == 0 && !local { return "", utils.ErrInfo(errors.New("Not local request from " + c.r.RemoteAddr)) } privKey := "" if len(c.r.FormValue("first")) > 0 { privKey, err = c.Single(`SELECT private_key FROM ` + c.MyPrefix + `my_keys WHERE status='my_pending'`).String() if err != nil { return "", utils.ErrInfo(err) } } else { privKey, _ = utils.GenKeys() } paramNoPass := utils.ParamType{X: 176, Y: 100, Width: 100, Bg_path: "static/img/k_bg.png"} paramPass := utils.ParamType{X: 167, Y: 93, Width: 118, Bg_path: "static/img/k_bg_pass.png"} var param utils.ParamType var privateKey string if len(c.r.FormValue("password")) > 0 { privateKey_, err := utils.Encrypt(utils.Md5(c.r.FormValue("password")), []byte(privKey)) privateKey = base64.StdEncoding.EncodeToString(privateKey_) if err != nil { return "", utils.ErrInfo(err) } param = paramPass } else { privateKey = strings.Replace(privKey, "-----BEGIN RSA PRIVATE KEY-----", "", -1) privateKey = strings.Replace(privateKey, "-----END RSA PRIVATE KEY-----", "", -1) param = paramNoPass } ios := false if ok, _ := regexp.MatchString("(iPod|iPhone|iPad)", c.r.UserAgent()); ok { ios = true } if len(c.r.FormValue("ios")) > 0 { ios = true } if ios || utils.Android() { buffer, err := utils.KeyToImg(privateKey, "", c.SessUserId, c.TimeFormat, param) if err != nil { return "", utils.ErrInfo(err) } c.w.Header().Set("Content-Type", "image/png") c.w.Header().Set("Content-Length", utils.IntToStr(len(buffer.Bytes()))) c.w.Header().Set("Content-Disposition", `attachment; filename="Dcoin-private-key-`+utils.Int64ToStr(c.SessUserId)+`.png"`) if _, err := c.w.Write(buffer.Bytes()); err != nil { return "", utils.ErrInfo(errors.New("unable to write image")) } } else { c.w.Header().Set("Content-Type", "text/plain") c.w.Header().Set("Content-Length", utils.IntToStr(len(privateKey))) c.w.Header().Set("Content-Disposition", `attachment; filename="Dcoin-private-key-`+utils.Int64ToStr(c.SessUserId)+`.txt"`) if _, err := c.w.Write([]byte(privateKey)); err != nil { return "", utils.ErrInfo(errors.New("unable to write text")) } } return "", nil }