func (c *Controller) Login() (string, error) { var pool_tech_works int funcMap := template.FuncMap{ "noescape": func(s string) template.HTML { return template.HTML(s) }, } data, err := static.Asset("static/templates/login.html") if err != nil { return "", err } modal, err := static.Asset("static/templates/modal.html") if err != nil { return "", err } t := template.Must(template.New("template").Funcs(funcMap).Parse(string(data))) t = template.Must(t.Parse(string(modal))) b := new(bytes.Buffer) // есть ли установочный пароль и был ли начально записан ключ var setupPassword bool if !c.Community { setupPassword_, err := c.Single("SELECT setup_password FROM config").String() if err != nil { return "", err } myKey, err := c.GetMyPublicKey(c.MyPrefix) if err != nil { return "", err } if len(myKey) == 0 && (len(setupPassword_) > 0 || setupPassword_ == string(utils.DSha256(""))) { setupPassword = true } } //fmt.Println(c.Lang) // проверим, не идут ли тех. работы на пуле if len(c.NodeConfig["pool_admin_user_id"]) > 0 && c.NodeConfig["pool_admin_user_id"] != utils.Int64ToStr(c.UserId) && c.NodeConfig["pool_tech_works"] == "1" && c.Community { pool_tech_works = 1 } else { pool_tech_works = 0 } err = t.ExecuteTemplate(b, "login", &loginStruct{ Lang: c.Lang, MyModalIdName: "myModalLogin", UserID: c.UserId, PoolTechWorks: pool_tech_works, SetupPassword: setupPassword, Community: c.Community, Desktop: utils.Desktop(), Mobile: utils.Mobile()}) if err != nil { return "", err } return b.String(), nil }
func (c *Controller) Chat() (string, error) { myChatName := utils.Int64ToStr(c.SessUserId) // возможно у отпарвителя есть ник name, err := c.Single(`SELECT name FROM users WHERE user_id = ?`, c.SessUserId).String() if err != nil { return "", utils.ErrInfo(err) } if len(name) > 0 { myChatName = name } TemplateStr, err := makeTemplate("chat", "chat", &chatPage{ Community: c.Community, CountSignArr: c.CountSignArr, CountSign: c.CountSign, Lang: c.Lang, ShowSignData: c.ShowSignData, SignData: "", MyChatName: myChatName, UserId: c.SessUserId, IOS: utils.IOS(), Mobile: utils.Mobile()}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) Upgrade5() (string, error) { log.Debug("Upgrade5") geolocationLat := "" geolocationLon := "" geolocation, err := c.Single("SELECT geolocation FROM " + c.MyPrefix + "my_table").String() if err != nil { return "", utils.ErrInfo(err) } if len(geolocation) > 0 { x := strings.Split(geolocation, ", ") if len(x) == 2 { geolocationLat = x[0] geolocationLon = x[1] } } saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "7", -1) upgradeMenu := utils.MakeUpgradeMenu(5) TemplateStr, err := makeTemplate("upgrade_5", "upgrade5", &upgrade5Page{ Alert: c.Alert, Lang: c.Lang, SaveAndGotoStep: saveAndGotoStep, UpgradeMenu: upgradeMenu, GeolocationLat: geolocationLat, GeolocationLon: geolocationLon, UserId: c.SessUserId, Mobile: utils.Mobile()}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func StartDaemons() { utils.DaemonsChans = nil daemonsStart := map[string]func(chBreaker chan bool, chAnswer chan string){"UnbanNodes": UnbanNodes, "FirstChangePkey": FirstChangePkey, "TestblockIsReady": TestblockIsReady, "TestblockGenerator": TestblockGenerator, "TestblockDisseminator": TestblockDisseminator, "Shop": Shop, "ReductionGenerator": ReductionGenerator, "QueueParserTx": QueueParserTx, "QueueParserTestblock": QueueParserTestblock, "QueueParserBlocks": QueueParserBlocks, "PctGenerator": PctGenerator, "Notifications": Notifications, "NodeVoting": NodeVoting, "MaxPromisedAmountGenerator": MaxPromisedAmountGenerator, "MaxOtherCurrenciesGenerator": MaxOtherCurrenciesGenerator, "ElectionsAdmin": ElectionsAdmin, "Disseminator": Disseminator, "Confirmations": Confirmations, "Connector": Connector, "Clear": Clear, "CleaningDb": CleaningDb, "CfProjects": CfProjects, "BlocksCollection": BlocksCollection, "Exchange": Exchange, "AutoUpdate": AutoUpdate} if utils.Mobile() { daemonsStart = map[string]func(chBreaker chan bool, chAnswer chan string){"UnbanNodes": UnbanNodes, "FirstChangePkey": FirstChangePkey, "QueueParserTx": QueueParserTx, "Notifications": Notifications, "Disseminator": Disseminator, "Confirmations": Confirmations, "Connector": Connector, "Clear": Clear, "CleaningDb": CleaningDb, "BlocksCollection": BlocksCollection} } if *utils.TestRollBack == 1 { daemonsStart = map[string]func(chBreaker chan bool, chAnswer chan string){"BlocksCollection": BlocksCollection} } if len(configIni["daemons"]) > 0 && configIni["daemons"] != "null" { daemonsConf := strings.Split(configIni["daemons"], ",") for _, fns := range daemonsConf { log.Debug("start daemon %s", fns) fmt.Println("start daemon ", fns) var chBreaker chan bool = make(chan bool, 1) var chAnswer chan string = make(chan string, 1) utils.DaemonsChans = append(utils.DaemonsChans, &utils.DaemonsChansType{ChBreaker: chBreaker, ChAnswer: chAnswer}) go daemonsStart[fns](chBreaker, chAnswer) } } else if configIni["daemons"] != "null" { for dName, fns := range daemonsStart { log.Debug("start daemon %s", dName) fmt.Println("start daemon ", fns) var chBreaker chan bool = make(chan bool, 1) var chAnswer chan string = make(chan string, 1) utils.DaemonsChans = append(utils.DaemonsChans, &utils.DaemonsChansType{ChBreaker: chBreaker, ChAnswer: chAnswer}) go fns(chBreaker, chAnswer) } } }
func (c *Controller) SetPassword() (string, error) { TemplateStr, err := makeTemplate("set_password", "setPassword", &setPasswordPage{ Lang: c.Lang, IOS: utils.IOS(), Android: utils.Android(), Mobile: utils.Mobile()}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) Upgrade4() (string, error) { log.Debug("Upgrade4") videoUrl := "" // есть ли загруженное видео. data, err := c.OneRow("SELECT video_url_id, video_type FROM " + c.MyPrefix + "my_table").String() if err != nil { return "", utils.ErrInfo(err) } switch data["video_type"] { case "youtube": videoUrl = "http://www.youtube.com/embed/" + data["video_url_id"] case "vimeo": videoUrl = "http://www.vimeo.com/embed/" + data["video_url_id"] case "youku": videoUrl = "http://www.youku.com/embed/" + data["video_url_id"] } saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "6", -1) upgradeMenu := utils.MakeUpgradeMenu(4) var userVideoMp4 string path := *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.mp4" if _, err := os.Stat(path); err == nil { userVideoMp4 = "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.mp4" } var userVideoWebm string path = *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.webm" if _, err := os.Stat(path); err == nil { userVideoWebm = "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.webm" } var userVideoOgg string path = *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.ogg" if _, err := os.Stat(path); err == nil { userVideoOgg = "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.ogg" } TemplateStr, err := makeTemplate("upgrade_4", "upgrade4", &upgrade4Page{ Alert: c.Alert, Lang: c.Lang, SaveAndGotoStep: saveAndGotoStep, UpgradeMenu: upgradeMenu, VideoUrl: videoUrl, UserVideoMp4: userVideoMp4, UserVideoWebm: userVideoWebm, UserVideoOgg: userVideoOgg, Mobile: utils.Mobile(), UserId: c.SessUserId}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) Notifications() (string, error) { if c.SessRestricted != 0 { return "", utils.ErrInfo(errors.New("Permission denied")) } var err error data, err := c.OneRow(` SELECT email, sms_http_get_request, use_smtp, smtp_server, smtp_port, smtp_ssl, smtp_auth, smtp_username, smtp_password FROM ` + c.MyPrefix + `my_table `).String() if err != nil { return "", utils.ErrInfo(err) } myNotifications := make(map[string]map[string]string) myNotifications_, err := c.GetAll("SELECT * FROM "+c.MyPrefix+"my_notifications ORDER BY sort ASC", -1) for _, data := range myNotifications_ { myNotifications[data["name"]] = map[string]string{"mobile": data["mobile"], "email": data["email"], "sms": data["sms"], "important": data["important"]} } log.Debug("myNotifications", myNotifications) TemplateStr, err := makeTemplate("notifications", "notifications", ¬ificationsPage{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, SignData: "", MyNotifications: myNotifications, NodeAdmin: c.NodeAdmin, LangInt: c.LangInt, Mobile: utils.Mobile(), Data: data}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) Upgrade1() (string, error) { log.Debug("Upgrade1") userFace := "" /*userProfile := "" path := "public/"+utils.Int64ToStr(c.SessUserId)+"_user_profile.jpg" if _, err := os.Stat(path); err == nil { userProfile = path }*/ path := *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg" if _, err := os.Stat(path); err == nil { userFace = "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg" } step := "1" nextStep := "2" photoType := "face" photo := userFace saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "3", -1) upgradeMenu := utils.MakeUpgradeMenu(1) TemplateStr, err := makeTemplate("upgrade_1_and_2", "upgrade1And2", &upgrade1Page{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, SaveAndGotoStep: saveAndGotoStep, UpgradeMenu: upgradeMenu, UserId: c.SessUserId, PhotoType: photoType, Photo: photo, Step: step, NextStep: nextStep, IOS: utils.IOS(), Mobile: utils.Mobile()}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) Upgrade0() (string, error) { log.Debug("first_select: %v", c.Parameters["first_select"]) if c.Parameters["first_select"] == "1" { c.ExecSql(`UPDATE ` + c.MyPrefix + `my_table SET first_select=1`) } data, err := c.OneRow("SELECT race, country FROM " + c.MyPrefix + "my_table").Int() if err != nil { return "", utils.ErrInfo(err) } race := data["race"] country := 0 if race > 0 { country = data["country"] } saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "2", -1) upgradeMenu := utils.MakeUpgradeMenu(0) TemplateStr, err := makeTemplate("upgrade_0", "upgrade0", &upgrade0Page{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, SaveAndGotoStep: saveAndGotoStep, UpgradeMenu: upgradeMenu, UserId: c.SessUserId, Countries: consts.Countries, Country: country, Race: race, Mobile: utils.Mobile()}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func ElectionsAdmin(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "ElectionsAdmin" d := new(daemon) d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } d.goRoutineName = GoroutineName d.chAnswer = chAnswer d.chBreaker = chBreaker if utils.Mobile() { d.sleepTime = 3600 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } err = d.notMinerSetSleepTime(1800) if err != nil { log.Error("%v", err) return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } blockId, err := d.GetBlockId() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if blockId == 0 { if d.unlockPrintSleep(utils.ErrInfo("blockId == 0"), d.sleepTime) { break BEGIN } continue BEGIN } _, _, myMinerId, _, _, _, err := d.TestBlock() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // а майнер ли я ? if myMinerId == 0 { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } variables, err := d.GetAllVariables() curTime := utils.Time() // проверим, прошло ли 2 недели с момента последнего обновления adminTime, err := d.Single("SELECT time FROM admin").Int64() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if curTime-adminTime <= variables.Int64["new_pct_period"] { if d.unlockPrintSleep(utils.ErrInfo("14 day error"), d.sleepTime) { break BEGIN } continue BEGIN } // сколько всего майнеров countMiners, err := d.Single("SELECT count(miner_id) FROM miners WHERE active = 1").Int64() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if countMiners < 1000 { if d.unlockPrintSleep(utils.ErrInfo("countMiners < 1000"), d.sleepTime) { break BEGIN } continue BEGIN } // берем все голоса var newAdmin int64 votes_admin, err := d.GetMap(` SELECT admin_user_id, count(user_id) as votes FROM votes_admin WHERE time > ? GROUP BY admin_user_id `, "admin_user_id", "votes", curTime-variables.Int64["new_pct_period"]) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for admin_user_id, votes := range votes_admin { // если более 50% майнеров проголосовали if utils.StrToInt64(votes) > countMiners/2 { newAdmin = utils.StrToInt64(admin_user_id) } } if newAdmin == 0 { if d.unlockPrintSleep(utils.ErrInfo("newAdmin == 0"), d.sleepTime) { break BEGIN } continue BEGIN } _, myUserId, _, _, _, _, err := d.TestBlock() forSign := fmt.Sprintf("%v,%v,%v,%v", utils.TypeInt("NewAdmin"), curTime, myUserId, newAdmin) 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("NewAdmin"), 1) data = append(data, utils.DecToBin(curTime, 4)...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(myUserId))...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(newAdmin))...) 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 } p := new(dcparser.Parser) p.DCDB = d.DCDB err = p.TxParser(utils.HexToBin(utils.Md5(data)), data, true) if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
/* если табла была очищена, то в parser.rollbackAI будет 0, поэтому нелья чистить таблы под нуль */ func Clear(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "Clear" 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 = 1800 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } blockId, err := d.GetBlockId() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if blockId == 0 { if d.unlockPrintSleep(utils.ErrInfo("blockId == 0"), d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("blockId: %d", blockId) variables, err := d.GetAllVariables() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // чистим log_transactions каждые 15 минут. Удаляем данные, которые старше 36 часов. // Можно удалять и те, что старше rollback_blocks_2 + погрешность для времени транзакции (5-15 мин), // но пусть будет 36 ч. - с хорошим запасом. err = d.ExecSql("DELETE FROM log_transactions WHERE time < ?", utils.Time()-86400*3) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // через rollback_blocks_2 с запасом 14400 блоков чистим таблу log_votes где есть del_block_id // при этом, если проверяющих будет мало, то табла может захламиться незаконченными голосованиями err = d.ExecSql("DELETE FROM log_votes WHERE del_block_id < ? AND del_block_id > 0", blockId-variables.Int64["rollback_blocks_2"]-14400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // через 14400 блоков чистим таблу wallets_buffer где есть del_block_id err = d.ExecSql("DELETE FROM wallets_buffer WHERE del_block_id < ? AND del_block_id > 0", blockId-variables.Int64["rollback_blocks_2"]-14400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // чистим все _log_time_ err = d.ExecSql("DELETE FROM log_time_votes_complex WHERE time < ?", utils.Time()-variables.Int64["limit_votes_complex_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_commission WHERE time < ?", utils.Time()-variables.Int64["limit_commission_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_change_host WHERE time < ?", utils.Time()-variables.Int64["limit_change_host_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_votes_miners WHERE time < ?", utils.Time()-variables.Int64["limit_votes_miners_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_primary_key WHERE time < ?", utils.Time()-variables.Int64["limit_primary_key_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_node_key WHERE time < ?", utils.Time()-variables.Int64["limit_node_key_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_mining WHERE time < ?", utils.Time()-variables.Int64["limit_mining_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_message_to_admin WHERE time < ?", utils.Time()-variables.Int64["limit_message_to_admin_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_holidays WHERE time < ?", utils.Time()-variables.Int64["limit_holidays_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_change_geolocation WHERE time < ?", utils.Time()-variables.Int64["limit_change_geolocation_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_cash_requests WHERE time < ?", utils.Time()-variables.Int64["limit_cash_requests_out_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_promised_amount WHERE time < ?", utils.Time()-variables.Int64["limit_promised_amount_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_abuses WHERE time < ?", utils.Time()-variables.Int64["limit_abuses_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_new_miner WHERE time < ?", utils.Time()-variables.Int64["limit_new_miner_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_votes WHERE time < ?", utils.Time()-86400-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_votes_nodes WHERE time < ?", utils.Time()-variables.Int64["node_voting_period"]-86400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_wallets WHERE block_id < ? AND block_id > 0", blockId-variables.Int64["rollback_blocks_2"]-14400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM log_time_money_orders WHERE del_block_id < ? AND del_block_id > 0", blockId-variables.Int64["rollback_blocks_2"]-14400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } arr := []string{"log_commission", "log_faces", "log_forex_orders", "log_forex_orders_main", "log_miners", "log_miners_data", "log_points", "log_promised_amount", "log_recycle_bin", "log_spots_compatibility", "log_users", "log_votes_max_other_currencies", "log_votes_max_promised_amount", "log_votes_miner_pct", "log_votes_reduction", "log_votes_user_pct", "log_wallets"} for _, table := range arr { err = d.ExecSql("DELETE FROM "+table+" WHERE block_id < ? AND block_id > 0", blockId-variables.Int64["rollback_blocks_2"]-14400) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } log.Debug("variables.Int64[rollback_blocks_2]: %v", variables.Int64["rollback_blocks_2"]) d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func Index(w http.ResponseWriter, r *http.Request) { r.ParseForm() parameters_ := make(map[string]interface{}) err := json.Unmarshal([]byte(r.PostFormValue("parameters")), ¶meters_) if err != nil { log.Error("%v", err) } log.Debug("parameters_=%", parameters_) parameters := make(map[string]string) for k, v := range parameters_ { parameters[k] = utils.InterfaceToStr(v) } lang := GetLang(w, r, parameters) sess, err := globalSessions.SessionStart(w, r) if err != nil { log.Error("%v", err) } defer sess.SessionRelease(w) sessUserId := GetSessUserId(sess) var key, myPrefix, status string var communityUsers []int64 var chatEnabled, analyticsDisabled string if utils.DB != nil && utils.DB.DB != nil { communityUsers, err = utils.DB.GetCommunityUsers() if err != nil { log.Error("%v", err) } if len(communityUsers) > 0 { myPrefix = utils.Int64ToStr(sessUserId) + "_" } status, err := utils.DB.Single("SELECT status FROM " + myPrefix + "my_table").String() // чтобы нельзя было зайти по локалке // :: - для маков if ok, _ := regexp.MatchString(`(\:\:)|(127\.0\.0\.1)`, r.RemoteAddr); ok { if status != "waiting_accept_new_key" && status != "waiting_set_new_key" { key, err = utils.DB.Single("SELECT private_key FROM " + myPrefix + "my_keys WHERE block_id = (SELECT max(block_id) FROM " + myPrefix + "my_keys)").String() if err != nil { log.Error("%v", err) } } } chatEnabled, err = utils.DB.Single(`SELECT chat_enabled FROM config`).String() if err != nil { log.Error("%v", err) } analyticsDisabled, err = utils.DB.Single(`SELECT analytics_disabled FROM config`).String() if err != nil { log.Error("%v", err) } } showIOSMenu := true // Когда меню не выдаем if utils.DB == nil || utils.DB.DB == nil { showIOSMenu = false } else { if status == "my_pending" { showIOSMenu = false } } if sessUserId == 0 { showIOSMenu = false } if showIOSMenu && utils.DB != nil && utils.DB.DB != nil { blockData, err := utils.DB.GetInfoBlock() if err != nil { log.Error("%v", err) } wTime := int64(12) wTimeReady := int64(2) log.Debug("wTime: %v / utils.Time(): %v / blockData[time]: %v", wTime, utils.Time(), utils.StrToInt64(blockData["time"])) // если время менее 12 часов от текущего, то выдаем не подвержденные, а просто те, что есть в блокчейне if utils.Time()-utils.StrToInt64(blockData["time"]) < 3600*wTime { lastBlockData, err := utils.DB.GetLastBlockData() if err != nil { log.Error("%v", err) } log.Debug("lastBlockData[lastBlockTime]: %v", lastBlockData["lastBlockTime"]) log.Debug("time.Now().Unix(): %v", utils.Time()) if utils.Time()-lastBlockData["lastBlockTime"] >= 3600*wTimeReady { showIOSMenu = false } } else { showIOSMenu = false } } if showIOSMenu && !utils.Mobile() { showIOSMenu = false } mobile := utils.Mobile() if ok, _ := regexp.MatchString("(?i)(iPod|iPhone|iPad|Android)", r.UserAgent()); ok { mobile = true } ios := utils.IOS() if ok, _ := regexp.MatchString("(?i)(iPod|iPhone|iPad)", r.UserAgent()); ok { ios = true } android := utils.Android() if ok, _ := regexp.MatchString("(?i)(Android)", r.UserAgent()); ok { android = true } var upgrade3 string if len(r.FormValue("upgrade3")) > 0 { upgrade3 = "1" } var upgrade4 string if len(r.FormValue("upgrade4")) > 0 { upgrade4 = "1" } formKey := r.FormValue("key") if len(formKey) > 0 { key = formKey // пишем в сессию, что бы ctrl+F5 не сбрасывал ключ (для авто-входа с dcoin.club) sess.Set("private_key", key) } else if len(key) == 0 { key = GetSessPrivateKey(w, r) } key = strings.Replace(key, "\r", "\n", -1) key = strings.Replace(key, "\n\n", "\n", -1) key = strings.Replace(key, "\n", "\\\n", -1) setLang := r.FormValue("lang") data, err := static.Asset("static/templates/index.html") t := template.New("template") t, err = t.Parse(string(data)) if err != nil { log.Error("%v", err) } b := new(bytes.Buffer) err = t.Execute(b, &index{ Upgrade3: upgrade3, Upgrade4: upgrade4, DbOk: true, Lang: globalLangReadOnly[lang], Key: key, SetLang: setLang, ShowIOSMenu: showIOSMenu, /*IOS: true, Android: false, Mobile: true})*/ IOS: ios, Android: android, ChatEnabled: chatEnabled, AnalyticsDisabled: analyticsDisabled, Mobile: mobile}) if err != nil { log.Error("%v", err) } w.Write(b.Bytes()) }
func Ajax(w http.ResponseWriter, r *http.Request) { defer func() { if r := recover(); r != nil { log.Error("ajax Recovered", r) fmt.Println("ajax Recovered", r) } }() log.Debug("Ajax") w.Header().Set("Content-type", "text/html") sess, err := globalSessions.SessionStart(w, r) if err != nil { log.Error("%v", err) return } defer sess.SessionRelease(w) sessUserId := GetSessUserId(sess) sessRestricted := GetSessRestricted(sess) sessPublicKey := GetSessPublicKey(sess) log.Debug("sessUserId", sessUserId) log.Debug("sessRestricted", sessRestricted) log.Debug("sessPublicKey", sessPublicKey) log.Debug("user_id: %v", sess.Get("user_id")) c := new(Controller) c.r = r c.w = w c.sess = sess c.SessRestricted = sessRestricted dbInit := false if len(configIni["db_user"]) > 0 || configIni["db_type"] == "sqlite" { dbInit = true } c.SessUserId = sessUserId if dbInit { var err error //c.DCDB, err = utils.NewDbConnect(configIni) c.DCDB = utils.DB if utils.DB == nil || utils.DB.DB == nil { log.Error("utils.DB == nil") dbInit = false } if dbInit { c.Variables, err = c.GetAllVariables() var communityUsers []int64 communityUsers, err = c.GetCommunityUsers() if err != nil { log.Error("%v", err) } c.CommunityUsers = communityUsers if len(communityUsers) > 0 { c.Community = true } if c.Community { poolAdminUserId, err := c.GetPoolAdminUserId() if err != nil { log.Error("%v", err) } c.PoolAdminUserId = poolAdminUserId if c.SessUserId == poolAdminUserId { c.PoolAdmin = true } c.MyPrefix = utils.Int64ToStr(sessUserId) + "_" } else { c.PoolAdmin = true } c.NodeAdmin, err = c.NodeAdminAccess(c.SessUserId, c.SessRestricted) if err != nil { log.Error("%v", err) } } } c.dbInit = dbInit c.Parameters, err = c.GetParameters() log.Debug("parameters=", c.Parameters) lang := GetLang(w, r, c.Parameters) log.Debug("lang", lang) c.Lang = globalLangReadOnly[lang] c.LangInt = int64(lang) if lang == 42 { c.TimeFormat = "2006-01-02 15:04:05" } else { c.TimeFormat = "2006-02-01 15:04:05" } if dbInit { myNotice, err := c.GetMyNoticeData(sessRestricted, sessUserId, c.MyPrefix, globalLangReadOnly[lang]) if err != nil { log.Error("%v", err) } c.MyNotice = myNotice config, err := c.GetNodeConfig() if err != nil { log.Error("%v", err) } c.NodeConfig = config // валюты c.CurrencyList, err = c.GetCurrencyList(false) if err != nil { log.Error("%v", err) } } r.ParseForm() controllerName := r.FormValue("controllerName") log.Debug("controllerName=", controllerName) html := "" //w.Header().Set("Access-Control-Allow-Origin", "*") if ok, _ := regexp.MatchString(`^(?i)RestartDb|RewritePrimaryKeySave|SendPromisedAmountToPool|SaveEmailAndSendTestMess|sendMobile|DebugInfo|rewritePrimaryKey|EImportData|EDataBaseDump|AlertFromAdmin|Update|UpdateDcoin|exchangeAdmin|newPhoto|NodeConfigControl|SaveDecryptComment|EncryptChatMessage|GetChatMessages|SendToTheChat|SaveToken|SendToPool|CheckSetupPassword|getBlock|AcceptNewKeyStatus|availableKeys|ClearDbLite|ClearDb|UploadVideo|DcoinKey|SynchronizationBlockchain|PoolAddUsers|SaveQueue|AlertMessage|Menu|SaveHost|GetMinerDataMap|SignUpInPool|Check_sign|PoolDataBaseDump|GetSellerData|GenerateNewPrimaryKey|GenerateNewNodeKey|CheckNode|SignLogin|SaveNotifications|ProgressBar|MinersMap|GetMinerData|EncryptComment|Logout|SaveVideo|SaveShopData|SaveRaceCountry|MyNoticeData|HolidaysList|ClearVideo|CheckCfCurrency|WalletsListCfProject|SendTestEmail|SendSms|SaveUserCoords|SaveGeolocation|SaveEmailSms|Profile|DeleteVideo|CropPhoto$`, controllerName); !ok { html = "Access denied 0" } else { pages := "RestartDb|DebugInfo|CheckSetupPassword|AcceptNewKeyStatus|availableKeys|CfCatalog|CfPagePreview|CfStart|Check_sign|CheckNode|GetBlock|GetMinerData|GetMinerDataMap|GetSellerData|Index|IndexCf|InstallStep0|InstallStep1|InstallStep2|Login|SynchronizationBlockchain|UpdatingBlockchain|Menu|SignUpInPool|SignLogin" if utils.Mobile() { // На IOS можно сгенерить ключ без сессии pages += "|DcoinKey" } if ok, _ := regexp.MatchString(`^(?i)`+pages+`$`, controllerName); !ok && c.SessUserId <= 0 { html = "Access denied 1" } else { // без БД будет выдавать панику if ok, _ := regexp.MatchString(`^(?i)GetChatMessages$`, controllerName); ok && !dbInit { html = "Please wait. nill dbInit" } else { // вызываем контроллер в зависимости от шаблона html, err = CallController(c, controllerName) if err != nil { log.Error("ajax error: %v", err) } } } } w.Write([]byte(html)) }
func FirstChangePkey(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "FirstChangePkey" 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 = 360 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } community, err := d.GetCommunityUsers() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } var uids []int64 if len(community) > 0 { uids = community } else { myuid, err := d.GetMyUserId("") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } uids = append(uids, myuid) } log.Debug("uids %v", uids) var status, myPrefix string for _, uid := range uids { if len(community) > 0 { myPrefix = utils.Int64ToStr(uid) + "_" } status, err = d.Single(`SELECT status FROM ` + myPrefix + `my_table`).String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("status: %v / myPrefix: %v", status, myPrefix) if status == "waiting_accept_new_key" { // если ключ кто-то сменил userPublicKey, err := d.GetUserPublicKey(uid) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } myUserPublicKey, err := d.GetMyPublicKey(myPrefix) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if !bytes.Equal(myUserPublicKey, []byte(userPublicKey)) { log.Debug("myUserPublicKey:%s != userPublicKey:%s", utils.BinToHex(myUserPublicKey), utils.BinToHex(userPublicKey)) // удаляем старый ключ err = d.ExecSql(`DELETE FROM ` + myPrefix + `my_keys`) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // и user_id q := `UPDATE ` + myPrefix + `my_table SET status="my_pending", user_id=0` if len(community) > 0 { q = `DELETE FROM ` + myPrefix + `my_table` } err = d.ExecSql(q) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(community) > 0 { err = d.ExecSql(`DELETE FROM community WHERE user_id = ?`, uid) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } // и пробуем взять новый availablekey := &availablekey.AvailablekeyStruct{} availablekey.DCDB = d.DCDB userId, _, err := availablekey.GetAvailableKey() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if userId > 0 { if len(community) > 0 { err = d.ExecSql(`INSERT INTO community (user_id) VALUES (?)`, userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } // генерим и шлем новую тр-ию err = d.SendTxChangePkey(userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } else { // если userId == 0, значит ключей в паблике больше нет и юзеру придется искать ключ самому continue } } // проверим, не прошла ли тр-ия и не сменился ли уже ключ userPubKeyCount, err := d.Single(`SELECT count(*) FROM ` + myPrefix + `my_keys WHERE status='approved'`).Int64() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("userPubKey: %v", userPubKeyCount) if userPubKeyCount > 1 { err = d.ExecSql(`UPDATE ` + myPrefix + `my_table SET status='user'`) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // также, если это пул, то надо удалить приватный ключ из базы данных, т.к. взлом пула будет означать угон всех акков // хранение ключа на мобильном - безопасно, хранение ключа на ПК, пока Dcoin не стал популярен, тоже допустимо if len(community) > 0 { err = d.ExecSql(`DELETE private_key FROM ` + myPrefix + `my_keys`) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } lastTx, err := d.GetLastTx(uid, utils.TypesToIds([]string{"ChangePrimaryKey"}), 1, "2006-02-01 15:04:05") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("lastTx: %v", lastTx) if len(lastTx) > 0 { if len(lastTx[0]["error"]) > 0 || utils.Time()-utils.StrToInt64(lastTx[0]["time_int"]) > 1800 { // генерим и шлем новую тр-ию err = d.SendTxChangePkey(uid) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } } } if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func TestblockIsReady(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "TestblockIsReady" 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 = 1 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { 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 } LocalGateIp, err := d.GetMyLocalGateIp() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } if len(LocalGateIp) > 0 { if d.dPrintSleep(utils.ErrInfo(errors.New("len(LocalGateIp) > 0")), d.sleepTime) { break BEGIN } continue } // сколько нужно спать prevBlock, myUserId, myMinerId, currentUserId, level, levelsRange, err := d.TestBlock() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } log.Info("%v", prevBlock, myUserId, myMinerId, currentUserId, level, levelsRange) if myMinerId == 0 { log.Debug("myMinerId == 0") if d.dSleep(d.sleepTime) { break BEGIN } continue } sleepData, err := d.GetSleepData() sleep := d.GetIsReadySleep(prevBlock.Level, sleepData["is_ready"]) prevHeadHash := prevBlock.HeadHash // Если случится откат или придет новый блок, то testblock станет неактуален startSleep := utils.Time() for i := 0; i < int(sleep); i++ { err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } newHeadHash, err := d.Single("SELECT head_hash FROM info_block").String() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } d.dbUnlock() newHeadHash = string(utils.BinToHex([]byte(newHeadHash))) if newHeadHash != prevHeadHash { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } log.Info("%v", "i", i, "time", utils.Time()) if utils.Time()-startSleep > sleep { break } utils.Sleep(1) // спим 1 сек. общее время = $sleep } /* Заголовок TYPE (0-блок, 1-тр-я) FF (256) BLOCK_ID FF FF FF FF (4 294 967 295) TIME FF FF FF FF (4 294 967 295) USER_ID FF FF FF FF FF (1 099 511 627 775) LEVEL FF (256) SIGN от 128 байта до 512 байт. Подпись от TYPE, BLOCK_ID, PREV_BLOCK_HASH, TIME, USER_ID, LEVEL, MRKL_ROOT Далее - тело блока (Тр-ии) */ // блокируем изменения данных в тестблоке // также, нужно блокировать main, т.к. изменение в info_block и block_chain ведут к изменению подписи в testblock err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // за промежуток в main_unlock и main_lock мог прийти новый блок prevBlock, myUserId, myMinerId, currentUserId, level, levelsRange, err = d.TestBlock() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } log.Info("%v", prevBlock, myUserId, myMinerId, currentUserId, level, levelsRange) // на всякий случай убедимся, что блок не изменился if prevBlock.HeadHash != prevHeadHash { if d.unlockPrintSleep(utils.ErrInfo(errors.New("prevBlock.HeadHash != prevHeadHash")), d.sleepTime) { break BEGIN } continue } // составим блок. заголовок + тело + подпись testBlockData, err := d.OneRow("SELECT * FROM testblock WHERE status = 'active'").String() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(errors.New("prevBlock.HeadHash != prevHeadHash")), d.sleepTime) { break BEGIN } continue } log.Debug("testBlockData: %v", testBlockData) if len(testBlockData) == 0 { if d.unlockPrintSleep(utils.ErrInfo(errors.New("null $testblock_data")), d.sleepTime) { break BEGIN } continue } // получим транзакции var testBlockDataTx []byte transactionsTestBlock, err := d.GetList("SELECT data FROM transactions_testblock ORDER BY id ASC").String() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for _, data := range transactionsTestBlock { testBlockDataTx = append(testBlockDataTx, utils.EncodeLengthPlusData([]byte(data))...) } // в промежутке межде тем, как блок был сгенерирован и запуском данного скрипта может измениться текущий блок // поэтому нужно проверять подпись блока из тестблока prevBlockHash, err := d.Single("SELECT hash FROM info_block").Bytes() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } prevBlockHash = utils.BinToHex(prevBlockHash) nodePublicKey, err := d.GetNodePublicKey(utils.StrToInt64(testBlockData["user_id"])) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } forSign := fmt.Sprintf("0,%v,%s,%v,%v,%v,%s", testBlockData["block_id"], prevBlockHash, testBlockData["time"], testBlockData["user_id"], testBlockData["level"], utils.BinToHex([]byte(testBlockData["mrkl_root"]))) log.Debug("forSign %v", forSign) log.Debug("signature %x", testBlockData["signature"]) p := new(dcparser.Parser) p.DCDB = d.DCDB // проверяем подпись _, err = utils.CheckSign([][]byte{nodePublicKey}, forSign, []byte(testBlockData["signature"]), true) if err != nil { log.Error("incorrect signature %v") p.RollbackTransactionsTestblock(true) err = d.ExecSql("DELETE FROM testblock") if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // БАГ if utils.StrToInt64(testBlockData["block_id"]) == prevBlock.BlockId { log.Error("testBlockData block_id = prevBlock.BlockId (%v=%v)", testBlockData["block_id"], prevBlock.BlockId) err = p.RollbackTransactionsTestblock(true) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM testblock") if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // готовим заголовок newBlockIdBinary := utils.DecToBin(utils.StrToInt64(testBlockData["block_id"]), 4) timeBinary := utils.DecToBin(utils.StrToInt64(testBlockData["time"]), 4) userIdBinary := utils.DecToBin(utils.StrToInt64(testBlockData["user_id"]), 5) levelBinary := utils.DecToBin(utils.StrToInt64(testBlockData["level"]), 1) //prevBlockHashBinary := prevBlock.Hash //merkleRootBinary := testBlockData["mrklRoot"]; // заголовок blockHeader := utils.DecToBin(0, 1) blockHeader = append(blockHeader, newBlockIdBinary...) blockHeader = append(blockHeader, timeBinary...) blockHeader = append(blockHeader, userIdBinary...) blockHeader = append(blockHeader, levelBinary...) blockHeader = append(blockHeader, utils.EncodeLengthPlusData([]byte(testBlockData["signature"]))...) // сам блок block := append(blockHeader, testBlockDataTx...) log.Debug("block %x", block) // теперь нужно разнести блок по таблицам и после этого мы будем его слать всем нодам скриптом disseminator.php p.BinaryData = block err = p.ParseDataFront() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // и можно удалять данные о тестблоке, т.к. они перешел в нормальный блок err = d.ExecSql("DELETE FROM transactions_testblock") if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM testblock") if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // между testblock_generator и testbock_is_ready p.RollbackTransactionsTestblock(false) d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func CfProjects(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "CfProjects" 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 = 1800 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // гео-декодирование all, err := d.GetAll(` SELECT id, latitude, longitude FROM cf_projects WHERE geo_checked= 0 `, -1) for _, cf_projects := range all { gmapData, err := utils.GetHttpTextAnswer("http://maps.googleapis.com/maps/api/geocode/json?latlng=" + cf_projects["latitude"] + "," + cf_projects["longitude"] + "&sensor=true_or_false") if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } var gmap map[string][]map[string][]map[string]string json.Unmarshal([]byte(gmapData), &gmap) if len(gmap["results"]) > 1 && len(gmap["results"][len(gmap["results"])-2]["address_components"]) > 0 { country := gmap["results"][len(gmap["results"])-2]["address_components"][0]["long_name"] city := gmap["results"][len(gmap["results"])-2]["address_components"][1]["short_name"] err = d.ExecSql("UPDATE cf_projects SET country = ?, city = ?, geo_checked= 1 WHERE id = ?", country, city, cf_projects["id"]) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } } // финансирование проектов cf_funding, err := d.GetAll(` SELECT id, project_id, amount FROM cf_funding WHERE checked= 0 `, -1) for _, data := range cf_funding { // отмечаем, чтобы больше не брать err = d.ExecSql("UPDATE cf_funding SET checked = 1 WHERE id = ?", data["id"]) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // сколько собрано средств funding, err := d.Single("SELECT sum(amount) FROM cf_funding WHERE project_id = ? AND del_block_id = 0", data["project_id"]).Float64() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // сколько всего фундеров countFunders, err := d.Single("SELECT count(id) FROM cf_funding WHERE project_id = ? AND del_block_id = 0 GROUP BY user_id", data["project_id"]).Int64() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // обновляем кол-во фундеров и собранные средства err = d.ExecSql("UPDATE cf_projects SET funding = ?, funders = ? WHERE id = ?", funding, countFunders, data["project_id"]) 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 Exchange(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "Exchange" d := new(daemon) d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } d.goRoutineName = GoroutineName d.chAnswer = chAnswer d.chBreaker = chBreaker if utils.Mobile() { d.sleepTime = 3600 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } blockId, err := d.GetConfirmedBlockId() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } var myPrefix string community, err := d.GetCommunityUsers() if len(community) > 0 { adminUserId, err := d.GetPoolAdminUserId() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } myPrefix = utils.Int64ToStr(adminUserId) + "_" } else { myPrefix = "" } eConfig, err := d.GetMap(`SELECT * FROM e_config`, "name", "value") if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } confirmations := utils.StrToInt64(eConfig["confirmations"]) mainDcAccount := utils.StrToInt64(eConfig["main_dc_account"]) // все валюты, с которыми работаем currencyList, err := utils.EGetCurrencyList() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // ++++++++++++ reduction ++++++++++++ // максимальный номер блока для процентов. Чтобы брать только новые maxReductionBlock, err := d.Single(`SELECT max(block_id) FROM e_reduction`).Int64() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // если есть свежая reduction, то нужно остановить торги reduction, err := d.Single(`SELECT block_id FROM reduction WHERE block_id > ? and pct > 0`, maxReductionBlock).Int64() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if reduction > 0 { err = d.ExecSql(`INSERT INTO e_reduction_lock (time) VALUES (?)`, utils.Time()) if err != nil { log.Error("%v", utils.ErrInfo(err)) } } // если уже прошло 10 блоков с момента обнаружения reduction, то производим сокращение объема монет rows, err := d.Query(d.FormatQuery(`SELECT pct, currency_id, time, block_id FROM reduction WHERE block_id > ? AND block_id < ?`), maxReductionBlock, blockId-confirmations) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var pct float64 var currencyId, rTime, blockId int64 err = rows.Scan(&pct, ¤cyId, &rTime, &blockId) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // $k = (100-$row['pct'])/100; k := (100 - pct) / 100 // уменьшаем все средства на счетах err = d.ExecSql(`UPDATE e_wallets SET amount = amount * ? WHERE currency_id = ?`, k, currencyId) // уменьшаем все средства на вывод err = d.ExecSql(`UPDATE e_withdraw SET amount = amount * ? WHERE currency_id = ? AND close_time = 0`, k, currencyId) // уменьшаем все ордеры на продажу err = d.ExecSql(`UPDATE e_orders SET amount = amount * ?, begin_amount = begin_amount * ? WHERE sell_currency_id = ?`, k, k, currencyId) err = d.ExecSql(`INSERT INTO e_reduction ( time, block_id, currency_id, pct ) VALUES ( ?, ?, ?, ? )`, rTime, blockId, currencyId, pct) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } rows.Close() // ++++++++++++ DC ++++++++++++ /* * Важно! отключать в кроне при обнулении данных в БД * * 1. Получаем инфу о входящих переводах и начисляем их на счета юзеров * 2. Обновляем проценты * 3. Чистим кол-во отправленных смс-ок * */ nodePrivateKey, err := d.GetNodePrivateKey(myPrefix) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } /* * Получаем инфу о входящих переводах и начисляем их на счета юзеров * */ // если всё остановлено из-за найденного блока с reduction, то входящие переводы не обрабатываем reductionLock, err := utils.EGetReductionLock() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if reductionLock > 0 { if d.dPrintSleep(utils.ErrInfo("reductionLock"), d.sleepTime) { break BEGIN } continue BEGIN } rows, err = d.Query(d.FormatQuery(` SELECT amount, id, block_id, type_id, currency_id, to_user_id, time, comment, comment_status FROM my_dc_transactions WHERE type = 'from_user' AND block_id < ? AND exchange_checked = 0 AND status = 'approved' AND to_user_id = ? ORDER BY id DESC`), blockId-confirmations, mainDcAccount) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var amount float64 var id, blockId, typeId, currencyId, toUserId, txTime int64 var comment, commentStatus string err = rows.Scan(&amount, &id, &blockId, &typeId, ¤cyId, &toUserId, &txTime, &comment, &commentStatus) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // отметим exchange_checked=1, чтобы больше не брать эту тр-ию err = d.ExecSql(`UPDATE my_dc_transactions SET exchange_checked = 1 WHERE id = ?`, id) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // вначале нужно проверить, точно ли есть такой перевод в блоке binaryData, err := d.Single(`SELECT data FROM block_chain WHERE id = ?`, blockId).Bytes() if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } p := new(dcparser.Parser) p.DCDB = d.DCDB p.BinaryData = binaryData p.ParseDataLite() for _, txMap := range p.TxMapArr { // пропускаем все ненужные тр-ии if utils.BytesToInt64(txMap["type"]) != utils.TypeInt("SendDc") { continue } log.Debug("md5hash %s", txMap["md5hash"]) // если что-то случится с таблой my_dc_transactions, то все ввода на биржу будут зачислены по новой // поэтому нужно проверять e_adding_funds exists, err := d.Single(`SELECT id FROM e_adding_funds WHERE hex(tx_hash) = ?`, string(txMap["md5hash"])).Int64() if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("exists %d", exists) if exists != 0 { continue } log.Debug("user_id = %d / typeId = %d / currency_id = %d / currencyId = %d / amount = %f / amount = %f / comment = %s / comment = %s / to_user_id = %d / toUserId = %d ", utils.BytesToInt64(txMap["user_id"]), typeId, utils.BytesToInt64(txMap["currency_id"]), currencyId, utils.BytesToFloat64(txMap["amount"]), amount, string(utils.BinToHex(txMap["comment"])), comment, utils.BytesToInt64(txMap["to_user_id"]), toUserId) // сравнение данных из таблы my_dc_transactions с тем, что в блоке if utils.BytesToInt64(txMap["user_id"]) == typeId && utils.BytesToInt64(txMap["currency_id"]) == currencyId && utils.BytesToFloat64(txMap["amount"]) == amount && string(utils.BinToHex(txMap["comment"])) == comment && utils.BytesToInt64(txMap["to_user_id"]) == toUserId { decryptedComment := comment if commentStatus == "encrypted" { // расшифруем коммент block, _ := pem.Decode([]byte(nodePrivateKey)) if block == nil || block.Type != "RSA PRIVATE KEY" { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } private_key, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } decryptedComment_, err := rsa.DecryptPKCS1v15(rand.Reader, private_key, utils.HexToBin(comment)) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } decryptedComment = string(decryptedComment_) // запишем расшифрованный коммент, чтобы потом можно было найти перевод в ручном режиме err = d.ExecSql("UPDATE "+myPrefix+"my_dc_transactions SET comment = ?, comment_status = 'decrypted' WHERE id = ?", decryptedComment, id) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } // возможно юзер сделал перевод в той валюте, которая у нас на бирже еще не торгуется if len(currencyList[currencyId]) == 0 { log.Error("currencyId %d not trading", currencyId) continue } // возможно, что чуть раньше было reduction, а это значит, что все тр-ии, // которые мы ещё не обработали и которые были До блока с reduction нужно принимать с учетом reduction // т.к. средства на нашем счете уже урезались, а вот те, что после reduction - остались в том виде, в котором пришли lastReduction, err := d.OneRow("SELECT block_id, pct FROM reduction WHERE currency_id = ? ORDER BY block_id", currencyId).Int64() if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if blockId <= lastReduction["block_id"] { // сумму с учетом reduction k0 := (100 - lastReduction["pct"]) / 100 amount = amount * float64(k0) } // начисляем средства на счет того, чей id указан в комменте r, _ := regexp.Compile(`(?i)\s*#\s*([0-9]+)\s*`) user := r.FindStringSubmatch(decryptedComment) if len(user) == 0 { log.Error("len(user) == 0") continue } log.Debug("user %s", user[1]) // user_id с биржевой таблы uid := utils.StrToInt64(user[1]) userAmountAndProfit := utils.EUserAmountAndProfit(uid, currencyId) newAmount_ := userAmountAndProfit + amount utils.UpdEWallet(uid, currencyId, utils.Time(), newAmount_, true) // для отчетности запишем в историю err = d.ExecSql(` INSERT INTO e_adding_funds ( user_id, currency_id, time, amount, tx_hash ) VALUES ( ?, ?, ?, ?, ? )`, uid, currencyId, txTime, amount, string(txMap["md5hash"])) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } } } rows.Close() /* * Обновляем проценты * */ // максимальный номер блока для процентов. Чтобы брать только новые maxPctBlock, err := d.Single(`SELECT max(block_id) FROM e_user_pct`).Int64() log.Debug(`SELECT time, block_id, currency_id, user FROM pct WHERE block_id < ` + utils.Int64ToStr(blockId-confirmations) + ` AND block_id > ` + utils.Int64ToStr(maxPctBlock)) rows, err = d.Query(d.FormatQuery(`SELECT time, block_id, currency_id, user FROM pct WHERE block_id < ? AND block_id > ?`), blockId-confirmations, maxPctBlock) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var pct float64 var pTime, blockId, currencyId int64 err = rows.Scan(&pTime, &blockId, ¤cyId, &pct) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } d.ExecSql(` INSERT INTO e_user_pct ( time, block_id, currency_id, pct ) VALUES ( ?, ?, ?, ? )`, pTime, blockId, currencyId, pct) } rows.Close() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
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 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 (c *Controller) Home() (string, error) { log.Debug("first_select: %v", c.Parameters["first_select"]) if c.Parameters["first_select"] == "1" { c.ExecSql(`UPDATE ` + c.MyPrefix + `my_table SET first_select=1`) } var publicKey []byte var poolAdmin bool var cashRequests int64 var showMap bool if c.SessRestricted == 0 { var err error publicKey, err = c.GetMyPublicKey(c.MyPrefix) if err != nil { return "", err } publicKey = utils.BinToHex(publicKey) cashRequests, err = c.Single("SELECT count(id) FROM cash_requests WHERE to_user_id = ? AND status = 'pending' AND for_repaid_del_block_id = 0 AND del_block_id = 0 and time > ?", c.SessUserId, utils.Time()-c.Variables.Int64["cash_request_time"]).Int64() fmt.Println("cashRequests", cashRequests) if err != nil { return "", err } show, err := c.Single("SELECT show_map FROM " + c.MyPrefix + "my_table").Int64() if err != nil { return "", err } if show > 0 { showMap = true } } if c.Community { poolAdminUserId, err := c.GetPoolAdminUserId() if err != nil { return "", err } if c.SessUserId == poolAdminUserId { poolAdmin = true } } wallets, err := c.GetBalances(c.SessUserId) if err != nil { return "", err } //var walletsByCurrency map[string]map[string]string walletsByCurrency := make(map[int]utils.DCAmounts) for _, data := range wallets { walletsByCurrency[int(data.CurrencyId)] = data } blockId, err := c.GetBlockId() if err != nil { return "", err } confirmedBlockId, err := c.GetConfirmedBlockId() if err != nil { return "", err } currencyList, err := c.GetCurrencyList(true) if err != nil { return "", err } for k, v := range currencyList { currencyList[k] = "d" + v } currencyList[1001] = "USD" // задания var assignments int64 count, err := c.Single("SELECT count(id) FROM votes_miners WHERE votes_end = 0 AND type = 'user_voting'").Int64() if err != nil { return "", err } assignments += count // вначале получим ID валют, которые мы можем проверять. currencyIds, err := c.GetList("SELECT currency_id FROM promised_amount WHERE status IN ('mining', 'repaid') AND user_id = ?", c.SessUserId).String() if len(currencyIds) > 0 || c.SessUserId == 1 { addSql := "" if c.SessUserId == 1 { addSql = "" } else { addSql = "AND currency_id IN (" + strings.Join(currencyIds, ",") + ")" } count, err := c.Single("SELECT count(id) FROM promised_amount WHERE status = 'pending' AND del_block_id = 0 " + addSql).Int64() if err != nil { return "", err } assignments += count } if c.SessRestricted == 0 { count, err := c.Single("SELECT count(id) FROM "+c.MyPrefix+"my_tasks WHERE time > ?", time.Now().Unix()-consts.ASSIGN_TIME).Int64() if err != nil { return "", err } assignments -= count if assignments < 0 { assignments = 0 } } // баллы points, err := c.Single("SELECT points FROM points WHERE user_id = ?", c.SessUserId).Int64() if err != nil { return "", err } currency_pct := make(map[int]CurrencyPct) // проценты listPct, err := c.GetMap("SELECT * FROM currency", "id", "name") for id, name := range listPct { pct, err := c.OneRow("SELECT * FROM pct WHERE currency_id = ? ORDER BY block_id DESC", id).Float64() if err != nil { return "", err } currency_pct[utils.StrToInt(id)] = CurrencyPct{Name: name, Miner: (utils.Round((math.Pow(1+pct["miner"], 3600*24*365)-1)*100, 2)), User: (utils.Round((math.Pow(1+pct["user"], 3600*24*365)-1)*100, 2)), MinerBlock: (utils.Round((math.Pow(1+pct["miner"], 120)-1)*100, 4)), UserBlock: (utils.Round((math.Pow(1+pct["user"], 120)-1)*100, 4)), MinerSec: (pct["miner"]), UserSec: (pct["user"])} } // случайне майнеры для нанесения на карту maxMinerId, err := c.Single("SELECT max(miner_id) FROM miners_data").Int64() if err != nil { return "", err } randMiners, err := c.GetList("SELECT user_id FROM miners_data WHERE status = 'miner' AND user_id > 7 AND user_id != 106 AND longitude > 0 AND miner_id IN (" + strings.Join(utils.RandSlice(1, maxMinerId, 3), ",") + ") LIMIT 3").Int64() if err != nil { return "", err } // получаем кол-во DC на кошельках sumWallets_, err := c.GetMap("SELECT currency_id, sum(amount) as sum_amount FROM wallets GROUP BY currency_id", "currency_id", "sum_amount") if err != nil { return "", err } sumWallets := make(map[int]float64) for currencyId, amount := range sumWallets_ { sumWallets[utils.StrToInt(currencyId)] = utils.StrToFloat64(amount) } // получаем кол-во TDC на обещанных суммах, плюсуем к тому, что на кошельках sumTdc, err := c.GetMap("SELECT currency_id, sum(tdc_amount) as sum_amount FROM promised_amount GROUP BY currency_id", "currency_id", "sum_amount") if err != nil { return "", err } for currencyId, amount := range sumTdc { currencyIdInt := utils.StrToInt(currencyId) if sumWallets[currencyIdInt] == 0 { sumWallets[currencyIdInt] = utils.StrToFloat64(amount) } else { sumWallets[currencyIdInt] += utils.StrToFloat64(amount) } } // получаем суммы обещанных сумм sumPromisedAmount, err := c.GetMap("SELECT currency_id, sum(amount) as sum_amount FROM promised_amount WHERE status = 'mining' AND del_block_id = 0 AND (cash_request_out_time = 0 OR cash_request_out_time > ?) GROUP BY currency_id", "currency_id", "sum_amount", time.Now().Unix()-c.Variables.Int64["cash_request_time"]) if err != nil { return "", err } _, _, promisedAmountListGen, err := c.GetPromisedAmounts(c.SessUserId, c.Variables.Int64["cash_request_time"]) calcTotal := utils.Round(100*math.Pow(1+currency_pct[72].MinerSec, 3600*24*30)-100, 0) // токен для запроса инфы с биржи var token, exchangeUrl string if c.SessRestricted == 0 { tokenAndUrl, err := c.OneRow(`SELECT token, e_host FROM ` + c.MyPrefix + `my_tokens LEFT JOIN miners_data ON miners_data.user_id = e_owner_id ORDER BY time DESC LIMIT 1`).String() if err != nil { return "", err } token = tokenAndUrl["token"] exchangeUrl = tokenAndUrl["e_host"] } myChatName := utils.Int64ToStr(c.SessUserId) // возможно у отпарвителя есть ник name, err := c.Single(`SELECT name FROM users WHERE user_id = ?`, c.SessUserId).String() if err != nil { return "", utils.ErrInfo(err) } if len(name) > 0 { myChatName = name } // получим топ 5 бирж topExMap := make(map[int64]*topEx) var q string if c.ConfigIni["db_type"] == "postgresql" { //q = "SELECT DISTINCT e_owner_id, e_host, count(votes_exchange.user_id), result from votes_exchange LEFT JOIN miners_data ON votes_exchange.e_owner_id = miners_data.user_id WHERE e_host != '' GROUP BY e_owner_id, result, e_host" q = "SELECT DISTINCT e_owner_id, e_host, count(votes_exchange.user_id), result from miners_data LEFT JOIN votes_exchange ON votes_exchange.e_owner_id = miners_data.user_id WHERE e_host != '' AND result >= 0 GROUP BY e_owner_id, result, e_host" } else { //q = "SELECT e_owner_id, e_host, count(votes_exchange.user_id) as count, result FROM miners_data LEFT JOIN votes_exchange ON votes_exchange.e_owner_id = miners_data.user_id WHERE and e_host != '' GROUP BY votes_exchange.e_owner_id, votes_exchange.result LIMIT 10" q = "SELECT e_owner_id, e_host, count(votes_exchange.user_id) as count, result FROM miners_data LEFT JOIN votes_exchange ON votes_exchange.e_owner_id = miners_data.user_id WHERE e_host != '' AND result >= 0 GROUP BY votes_exchange.e_owner_id, votes_exchange.result LIMIT 10" } rows, err := c.Query(q) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() for rows.Next() { var user_id, count, result int64 var e_host []byte err = rows.Scan(&user_id, &e_host, &count, &result) if err != nil { return "", utils.ErrInfo(err) } if topExMap[user_id] == nil { topExMap[user_id] = new(topEx) } //if len(topExMap[user_id].Host) == 0 { // topExMap[user_id] = new(topEx) if result == 0 { topExMap[user_id].Vote1 = count } else { topExMap[user_id].Vote1 = count } topExMap[user_id].Host = string(e_host) topExMap[user_id].UserId = user_id //} } // майнер ли я? miner_, err := c.Single(`SELECT miner_id FROM miners_data WHERE user_id = ?`, c.SessUserId).Int64() if err != nil { return "", utils.ErrInfo(err) } var miner bool if miner_ > 0 { miner = true } TemplateStr, err := makeTemplate("home", "home", &homePage{ Community: c.Community, CountSignArr: c.CountSignArr, CountSign: c.CountSign, CalcTotal: calcTotal, Admin: c.Admin, CurrencyPct: currency_pct, SumWallets: sumWallets, Wallets: walletsByCurrency, PromisedAmountListGen: promisedAmountListGen, SessRestricted: c.SessRestricted, SumPromisedAmount: sumPromisedAmount, RandMiners: randMiners, Points: points, Assignments: assignments, CurrencyList: currencyList, ConfirmedBlockId: confirmedBlockId, CashRequests: cashRequests, ShowMap: showMap, BlockId: blockId, UserId: c.SessUserId, PoolAdmin: poolAdmin, Alert: c.Alert, MyNotice: c.MyNotice, Lang: c.Lang, Title: c.Lang["geolocation"], ShowSignData: c.ShowSignData, SignData: "", MyChatName: myChatName, IOS: utils.IOS(), Mobile: utils.Mobile(), TopExMap: topExMap, ChatEnabled: c.NodeConfig["chat_enabled"], Miner: miner, Token: token, ExchangeUrl: exchangeUrl}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func QueueParserBlocks(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "QueueParserBlocks" 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 = 1800 } else { d.sleepTime = 10 } 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 } err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } prevBlockData, err := d.OneRow("SELECT * FROM info_block").String() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } newBlockData, err := d.OneRow("SELECT * FROM queue_blocks").String() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if len(newBlockData) == 0 { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } newBlockData["head_hash_hex"] = string(utils.BinToHex(newBlockData["head_hash"])) prevBlockData["head_hash_hex"] = string(utils.BinToHex(prevBlockData["head_hash"])) newBlockData["hash_hex"] = string(utils.BinToHex(newBlockData["hash"])) prevBlockData["hash_hex"] = string(utils.BinToHex(prevBlockData["hash"])) variables, err := d.GetAllVariables() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } /* * Базовая проверка */ // проверим, укладывается ли блок в лимит rollback_blocks_1 if utils.StrToInt64(newBlockData["block_id"]) > utils.StrToInt64(prevBlockData["block_id"])+variables.Int64["rollback_blocks_1"] { d.DeleteQueueBlock(newBlockData["head_hash_hex"], newBlockData["hash_hex"]) if d.unlockPrintSleep(utils.ErrInfo("rollback_blocks_1"), 1) { break BEGIN } continue BEGIN } // проверим не старый ли блок в очереди if utils.StrToInt64(newBlockData["block_id"]) < utils.StrToInt64(prevBlockData["block_id"]) { d.DeleteQueueBlock(newBlockData["head_hash_hex"], newBlockData["hash_hex"]) if d.unlockPrintSleep(utils.ErrInfo("old block"), 1) { break BEGIN } continue BEGIN } if utils.StrToInt64(newBlockData["block_id"]) == utils.StrToInt64(prevBlockData["block_id"]) { // сравним хэши hash1 := big.NewInt(0) hash1.SetString(string(newBlockData["head_hash_hex"]), 16) hash2 := big.NewInt(0) hash2.SetString(string(prevBlockData["head_hash_hex"]), 16) // newBlockData["head_hash_hex"]) <= prevBlockData["head_hash_hex"] if hash1.Cmp(hash2) < 1 { // если это тотже блок и его генерил тот же юзер, то могут быть равные head_hash if hash1.Cmp(hash2) == 0 { // в этом случае проверяем вторые хэши. Если новый блок имеет больший хэш, то нам он не нужен // или если тот же хэш, значит блоки одинаковые hash1 := big.NewInt(0) hash1.SetString(string(newBlockData["hash_hex"]), 16) hash2 := big.NewInt(0) hash2.SetString(string(prevBlockData["hash_hex"]), 16) // newBlockData["head_hash_hex"]) >= prevBlockData["head_hash_hex"] if hash1.Cmp(hash2) >= 0 { d.DeleteQueueBlock(newBlockData["head_hash_hex"], newBlockData["hash_hex"]) if d.unlockPrintSleep(utils.ErrInfo("newBlockData hash_hex == prevBlockData hash_hex"), 1) { break BEGIN } continue BEGIN } } } else { d.DeleteQueueBlock(newBlockData["head_hash_hex"], newBlockData["hash_hex"]) if d.unlockPrintSleep(utils.ErrInfo("newBlockData head_hash_hex > prevBlockData head_hash_hex"), 1) { break BEGIN } continue BEGIN } } /* * Загрузка блоков для детальной проверки */ host, err := d.Single("SELECT tcp_host FROM miners_data WHERE user_id = ?", newBlockData["user_id"]).String() if err != nil { d.DeleteQueueBlock(newBlockData["head_hash_hex"], newBlockData["hash_hex"]) if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } blockId := utils.StrToInt64(newBlockData["block_id"]) p := new(dcparser.Parser) p.DCDB = d.DCDB p.GoroutineName = GoroutineName err = p.GetBlocks(blockId, host, utils.StrToInt64(newBlockData["user_id"]), "rollback_blocks_1", GoroutineName, 7, "") if err != nil { log.Error("v", err) d.DeleteQueueBlock(newBlockData["head_hash_hex"], newBlockData["hash_hex"]) d.NodesBan(utils.StrToInt64(newBlockData["user_id"]), fmt.Sprintf("%v", err)) if d.unlockPrintSleep(utils.ErrInfo(err), 1) { break BEGIN } continue BEGIN } d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
/* * Каждые 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) }
/* * Каждые 2 недели собираем инфу о голосах за % и создаем тр-ию, которая * попадет в DC сеть только, если мы окажемся генератором блока * */ func PctGenerator(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "PctGenerator" d := new(daemon) d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } d.goRoutineName = GoroutineName d.chAnswer = chAnswer d.chBreaker = chBreaker if utils.Mobile() { d.sleepTime = 3600 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } err = d.notMinerSetSleepTime(1800) if err != nil { log.Error("%v", err) return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } blockId, err := d.GetBlockId() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if blockId == 0 { if d.unlockPrintSleep(utils.ErrInfo("blockId == 0"), d.sleepTime) { break BEGIN } continue BEGIN } _, _, myMinerId, _, _, _, err := d.TestBlock() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // а майнер ли я ? if myMinerId == 0 { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } variables, err := d.GetAllVariables() curTime := utils.Time() // проверим, прошло ли 2 недели с момента последнего обновления pct pctTime, err := d.Single("SELECT max(time) FROM pct").Int64() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if curTime-pctTime > variables.Int64["new_pct_period"] { // берем все голоса miner_pct pctVotes := make(map[int64]map[string]map[string]int64) rows, err := d.Query("SELECT currency_id, pct, count(user_id) as votes FROM votes_miner_pct GROUP BY currency_id, pct ORDER BY currency_id, pct ASC") if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var currency_id, votes int64 var pct string err = rows.Scan(¤cy_id, &pct, &votes) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } log.Info("%v", "newpctcurrency_id", currency_id, "pct", pct, "votes", votes) if len(pctVotes[currency_id]) == 0 { pctVotes[currency_id] = make(map[string]map[string]int64) } if len(pctVotes[currency_id]["miner_pct"]) == 0 { pctVotes[currency_id]["miner_pct"] = make(map[string]int64) } pctVotes[currency_id]["miner_pct"][pct] = votes } rows.Close() // берем все голоса user_pct rows, err = d.Query("SELECT currency_id, pct, count(user_id) as votes FROM votes_user_pct GROUP BY currency_id, pct ORDER BY currency_id, pct ASC") if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var currency_id, votes int64 var pct string err = rows.Scan(¤cy_id, &pct, &votes) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } log.Info("%v", "currency_id", currency_id, "pct", pct, "votes", votes) if len(pctVotes[currency_id]) == 0 { pctVotes[currency_id] = make(map[string]map[string]int64) } if len(pctVotes[currency_id]["user_pct"]) == 0 { pctVotes[currency_id]["user_pct"] = make(map[string]int64) } pctVotes[currency_id]["user_pct"][pct] = votes } rows.Close() newPct := make(map[string]map[string]map[string]string) newPct["currency"] = make(map[string]map[string]string) var userMaxKey int64 PctArray := utils.GetPctArray() log.Info("%v", "pctVotes", pctVotes) for currencyId, data := range pctVotes { currencyIdStr := utils.Int64ToStr(currencyId) // определяем % для майнеров pctArr := utils.MakePctArray(data["miner_pct"]) log.Info("%v", "pctArrminer_pct", pctArr, currencyId) key := utils.GetMaxVote(pctArr, 0, 390, 100) log.Info("%v", "key", key) if len(newPct["currency"][currencyIdStr]) == 0 { newPct["currency"][currencyIdStr] = make(map[string]string) } newPct["currency"][currencyIdStr]["miner_pct"] = utils.GetPctValue(key) // определяем % для юзеров pctArr = utils.MakePctArray(data["user_pct"]) log.Info("%v", "pctArruser_pct", pctArr, currencyId) log.Info("%v", "newPct", newPct) pctY := utils.ArraySearch(newPct["currency"][currencyIdStr]["miner_pct"], PctArray) log.Info("%v", "newPct[currency][currencyIdStr][miner_pct]", newPct["currency"][currencyIdStr]["miner_pct"]) log.Info("%v", "PctArray", PctArray) log.Info("%v", "miner_pct $pct_y=", pctY) maxUserPctY := utils.Round(utils.StrToFloat64(pctY)/2, 2) userMaxKey = utils.FindUserPct(int(maxUserPctY)) log.Info("%v", "maxUserPctY", maxUserPctY, "userMaxKey", userMaxKey, "currencyIdStr", currencyIdStr) // отрезаем лишнее, т.к. поиск идет ровно до макимального возможного, т.е. до miner_pct/2 pctArr = utils.DelUserPct(pctArr, userMaxKey) log.Info("%v", "pctArr", pctArr) key = utils.GetMaxVote(pctArr, 0, userMaxKey, 100) log.Info("%v", "data[user_pct]", data["user_pct"]) log.Info("%v", "pctArr", pctArr) log.Info("%v", "userMaxKey", userMaxKey) log.Info("%v", "key", key) newPct["currency"][currencyIdStr]["user_pct"] = utils.GetPctValue(key) log.Info("%v", "user_pct", newPct["currency"][currencyIdStr]["user_pct"]) } newPct_ := new(newPctType) newPct_.Currency = make(map[string]map[string]string) newPct_.Currency = newPct["currency"] newPct_.Referral = make(map[string]int64) refLevels := []string{"first", "second", "third"} for i := 0; i < len(refLevels); i++ { level := refLevels[i] var votesReferral []map[int64]int64 // берем все голоса rows, err := d.Query("SELECT " + level + ", count(user_id) as votes FROM votes_referral GROUP BY " + level + " ORDER BY " + level + " ASC ") if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var level_, votes int64 err = rows.Scan(&level_, &votes) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } votesReferral = append(votesReferral, map[int64]int64{level_: votes}) } rows.Close() newPct_.Referral[level] = (utils.GetMaxVote(votesReferral, 0, 30, 10)) } jsonData, err := json.Marshal(newPct_) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } _, myUserId, _, _, _, _, err := d.TestBlock() forSign := fmt.Sprintf("%v,%v,%v,%s", utils.TypeInt("NewPct"), curTime, myUserId, jsonData) log.Debug("forSign = %v", forSign) binSign, err := d.GetBinSign(forSign, myUserId) log.Debug("binSign = %x", binSign) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } data := utils.DecToBin(utils.TypeInt("NewPct"), 1) data = append(data, utils.DecToBin(curTime, 4)...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(myUserId))...) data = append(data, utils.EncodeLengthPlusData(jsonData)...) data = append(data, utils.EncodeLengthPlusData([]byte(binSign))...) err = d.InsertReplaceTxInQueue(data) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // и не закрывая main_lock переводим нашу тр-ию в verified=1, откатив все несовместимые тр-ии // таким образом у нас будут в блоке только актуальные голоса. // а если придет другой блок и станет verified=0, то эта тр-ия просто удалится. p := new(dcparser.Parser) p.DCDB = d.DCDB err = p.TxParser(utils.HexToBin(utils.Md5(data)), data, true) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func NodeVoting(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "NodeVoting" 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 } // берем данные, которые находятся на голосовании нодов rows, err := d.Query(d.FormatQuery(` SELECT miners_data.user_id, http_host as host, face_hash, profile_hash, photo_block_id, photo_max_miner_id, miners_keepers, id as vote_id, miner_id FROM votes_miners LEFT JOIN miners_data ON votes_miners.user_id = miners_data.user_id WHERE cron_checked_time < ? AND votes_end = 0 AND type = 'node_voting' `), utils.Time()-consts.CRON_CHECKED_TIME_SEC) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if ok := rows.Next(); ok { var vote_id, miner_id int64 var user_id, host, row_face_hash, row_profile_hash, photo_block_id, photo_max_miner_id, miners_keepers string err = rows.Scan(&user_id, &host, &row_face_hash, &row_profile_hash, &photo_block_id, &photo_max_miner_id, &miners_keepers, &vote_id, &miner_id) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { rows.Close() utils.Sleep(1) break } minersIds := utils.GetMinersKeepers(photo_block_id, photo_max_miner_id, miners_keepers, true) myUsersIds, err := d.GetMyUsersIds(true, true) myMinersIds, err := d.GetMyMinersIds(myUsersIds) // нет ли нас среди тех, кто должен скачать фото к себе и проголосовать var intersectMyMiners []int64 for _, id := range minersIds { if utils.InSliceInt64(int64(id), myMinersIds) { intersectMyMiners = append(intersectMyMiners, int64(id)) } } var vote int64 if len(intersectMyMiners) > 0 { var downloadError bool var faceHash, profileHash string var faceFile, profileFile []byte // копируем фото к себе profilePath := *utils.Dir + "/public/profile_" + user_id + ".jpg" _, err = utils.DownloadToFile(host+"/public/"+user_id+"_user_profile.jpg", profilePath, 60, chBreaker, chAnswer, GoroutineName) if err != nil { log.Error("%s", utils.ErrInfo(err)) downloadError = true } facePath := *utils.Dir + "/public/face_" + user_id + ".jpg" _, err = utils.DownloadToFile(host+"/public/"+user_id+"_user_face.jpg", facePath, 60, chBreaker, chAnswer, GoroutineName) if err != nil { log.Error("%s", utils.ErrInfo(err)) downloadError = true } if !downloadError { // хэши скопированных фото profileFile, err = ioutil.ReadFile(profilePath) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } profileHash = string(utils.DSha256(profileFile)) log.Info("%v", "profileHash", profileHash) faceFile, err = ioutil.ReadFile(facePath) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } faceHash = string(utils.DSha256(faceFile)) log.Info("%v", "faceHash", faceHash) } // проверяем хэш. Если сходится, то голосуем за, если нет - против и размер не должен быть более 200 Kb. if profileHash == row_profile_hash && faceHash == row_face_hash && len(profileFile) < 204800 && len(faceFile) < 204800 { vote = 1 } else { log.Error("%s %s %s %s %d %d", profileHash, row_face_hash, faceHash, row_profile_hash, len(profileFile), len(faceFile)) vote = 0 // если хэш не сходится, то удаляем только что скаченное фото os.Remove(profilePath) os.Remove(facePath) } // проходимся по всем нашим майнерам, если это пул и по одному, если это сингл-мод for _, myMinerId := range intersectMyMiners { myUserId, err := d.Single("SELECT user_id FROM miners_data WHERE miner_id = ?", myMinerId).Int64() if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } curTime := utils.Time() forSign := fmt.Sprintf("%v,%v,%v,%v,%v", utils.TypeInt("VotesNodeNewMiner"), curTime, myUserId, vote_id, vote) binSign, err := d.GetBinSign(forSign, myUserId) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } data := utils.DecToBin(utils.TypeInt("VotesNodeNewMiner"), 1) data = append(data, utils.DecToBin(curTime, 4)...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(myUserId))...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(vote_id))...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(vote))...) data = append(data, utils.EncodeLengthPlusData([]byte(binSign))...) err = d.InsertReplaceTxInQueue(data) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } } // отмечаем, чтобы больше не брать эту строку err = d.ExecSql("UPDATE votes_miners SET cron_checked_time = ? WHERE id = ?", utils.Time(), vote_id) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } rows.Close() d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
/** * Демон, который мониторит таблу testblock и если видит status=active, * то шлет блок строго тем, кто находятся на одном с нами уровне. Если пошлет * тем, кто не на одном уровне, то блок просто проигнорируется * */ func TestblockDisseminator(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "TestblockDisseminator" 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 = 1 } 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 } nodeConfig, err := d.GetNodeConfig() if len(nodeConfig["local_gate_ip"]) != 0 { if d.dPrintSleep("local_gate_ip", d.sleepTime) { break BEGIN } continue } _, _, _, _, level, levelsRange, err := d.TestBlock() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } log.Debug("level: %v", level) log.Debug("levelsRange: %v", levelsRange) // получим id майнеров, которые на нашем уровне nodesIds := utils.GetOurLevelNodes(level, levelsRange) if len(nodesIds) == 0 { log.Debug("len(nodesIds) == 0") if d.dSleep(d.sleepTime) { break BEGIN } continue } log.Debug("nodesIds: %v", nodesIds) // получим хосты майнеров, которые на нашем уровне hosts_, err := d.GetList("SELECT tcp_host FROM miners_data WHERE miner_id IN (" + strings.Join(utils.SliceInt64ToString(nodesIds), `,`) + ")").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } hosts := []string{} for _, host := range hosts_ { if !stringInSlice(host, hosts) { hosts = append(hosts, host) } } log.Debug("hosts: %v", hosts) // шлем block_id, user_id, mrkl_root, signature data, err := d.OneRow("SELECT block_id, time, user_id, mrkl_root, signature FROM testblock WHERE status = 'active' AND sent=0").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } if len(data) > 0 { err = d.ExecSql("UPDATE testblock SET sent=1") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } dataToBeSent := utils.DecToBin(utils.StrToInt64(data["block_id"]), 4) dataToBeSent = append(dataToBeSent, utils.DecToBin(data["time"], 4)...) dataToBeSent = append(dataToBeSent, utils.DecToBin(data["user_id"], 4)...) dataToBeSent = append(dataToBeSent, []byte(data["mrkl_root"])...) dataToBeSent = append(dataToBeSent, utils.EncodeLengthPlusData(data["signature"])...) for _, host := range hosts { go func(host string) { log.Debug("host: %v", host) conn, err := utils.TcpConn(host) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } defer conn.Close() // вначале шлем тип данных _, err = conn.Write(utils.DecToBin(6, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // в 4-х байтах пишем размер данных, которые пошлем далее _, err = conn.Write(utils.DecToBin(len(dataToBeSent), 4)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // далее шлем сами данные log.Debug("dataToBeSent: %x", dataToBeSent) _, err = conn.Write(dataToBeSent) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } /* * Получаем тр-ии, которые есть у юзера, в ответ выдаем те, что недостают и * их порядок следования, чтобы получить валидный блок */ buf := make([]byte, 4) _, err = conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } dataSize := utils.BinToDec(buf) // и если данных менее 10мб, то получаем их if dataSize < 10485760 { data, err := d.OneRow("SELECT * FROM testblock").String() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } responseBinaryData := utils.DecToBin(utils.StrToInt64(data["block_id"]), 4) responseBinaryData = append(responseBinaryData, utils.DecToBin(utils.StrToInt64(data["time"]), 4)...) responseBinaryData = append(responseBinaryData, utils.DecToBin(utils.StrToInt64(data["user_id"]), 5)...) responseBinaryData = append(responseBinaryData, utils.EncodeLengthPlusData(data["signature"])...) addSql := "" if dataSize > 0 { binaryData := make([]byte, dataSize) _, err := conn.Read(binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // разбираем присланные данные // получим хэши тр-ий, которые надо исключить for { if len(binaryData) < 16 { break } txHex := utils.BinToHex(utils.BytesShift(&binaryData, 16)) // проверим addSql += string(txHex) + "," if len(binaryData) == 0 { break } } addSql = addSql[:len(addSql)-1] addSql = "WHERE id NOT IN (" + addSql + ")" } // сами тр-ии var transactions []byte transactions_testblock, err := d.GetList(`SELECT data FROM transactions_testblock ` + addSql).String() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } for _, txData := range transactions_testblock { transactions = append(transactions, utils.EncodeLengthPlusData(txData)...) } responseBinaryData = append(responseBinaryData, utils.EncodeLengthPlusData(transactions)...) // порядок тр-ий transactions_testblock, err = d.GetList(`SELECT hash FROM transactions_testblock ORDER BY id ASC`).String() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } for _, txHash := range transactions_testblock { responseBinaryData = append(responseBinaryData, []byte(txHash)...) } // в 4-х байтах пишем размер данных, которые пошлем далее _, err = conn.Write(utils.DecToBin(len(responseBinaryData), 4)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // далее шлем сами данные _, err = conn.Write(responseBinaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } }(host) } } if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func BlocksCollection(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "BlocksCollection" d := new(daemon) d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } d.goRoutineName = GoroutineName d.chAnswer = chAnswer d.chBreaker = chBreaker if utils.Mobile() { d.sleepTime = 300 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } //var cur bool BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } log.Debug("0") config, err := d.GetNodeConfig() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("1") err, restart := d.dbLock() if restart { log.Debug("restart true") break BEGIN } if err != nil { log.Debug("restart err %v", err) if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("2") // если это первый запуск во время инсталяции currentBlockId, err := d.GetBlockId() if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Info("config", config) log.Info("currentBlockId", currentBlockId) // на время тестов /*if !cur { currentBlockId = 0 cur = true }*/ parser := new(dcparser.Parser) parser.DCDB = d.DCDB parser.GoroutineName = GoroutineName if currentBlockId == 0 || *utils.StartBlockId > 0 { /* IsNotExistBlockChain := false if _, err := os.Stat(*utils.Dir+"/public/blockchain"); os.IsNotExist(err) { IsNotExistBlockChain = true }*/ if config["first_load_blockchain"] == "file" /* && IsNotExistBlockChain*/ { log.Info("first_load_blockchain=file") nodeConfig, err := d.GetNodeConfig() blockchain_url := nodeConfig["first_load_blockchain_url"] if len(blockchain_url) == 0 { blockchain_url = consts.BLOCKCHAIN_URL } log.Debug("blockchain_url: %s", blockchain_url) // возможно сервер отдаст блокчейн не с первой попытки var blockchainSize int64 for i := 0; i < 10; i++ { log.Debug("blockchain_url: %s, i: %d", blockchain_url, i) blockchainSize, err = utils.DownloadToFile(blockchain_url, *utils.Dir+"/public/blockchain", 3600, chBreaker, chAnswer, GoroutineName) if err != nil { log.Error("%v", utils.ErrInfo(err)) } if blockchainSize > consts.BLOCKCHAIN_SIZE { break } } log.Debug("blockchain dw ok") if err != nil || blockchainSize < consts.BLOCKCHAIN_SIZE { if err != nil { log.Error("%v", utils.ErrInfo(err)) } else { log.Info(fmt.Sprintf("%v < %v", blockchainSize, consts.BLOCKCHAIN_SIZE)) } if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } first := true /*// блокчейн мог быть загружен ранее. проверим его размер stat, err := file.Stat() if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } file.Close() continue BEGIN } if stat.Size() < consts.BLOCKCHAIN_SIZE { d.unlockPrintSleep(fmt.Errorf("%v < %v", stat.Size(), consts.BLOCKCHAIN_SIZE), 1) file.Close() continue BEGIN }*/ log.Debug("GO!") file, err := os.Open(*utils.Dir + "/public/blockchain") if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql(`UPDATE config SET current_load_blockchain = 'file'`) if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for { // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { d.unlockPrintSleep(fmt.Errorf("DaemonsRestart"), 0) break BEGIN } b1 := make([]byte, 5) file.Read(b1) dataSize := utils.BinToDec(b1) log.Debug("dataSize", dataSize) if dataSize > 0 { data := make([]byte, dataSize) file.Read(data) //log.Debug("data %x\n", data) blockId := utils.BinToDec(data[0:5]) if *utils.EndBlockId > 0 && blockId == *utils.EndBlockId { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } file.Close() continue BEGIN } log.Info("blockId", blockId) data2 := data[5:] length := utils.DecodeLength(&data2) log.Debug("length", length) //log.Debug("data2 %x\n", data2) blockBin := utils.BytesShift(&data2, length) //log.Debug("blockBin %x\n", blockBin) if *utils.StartBlockId == 0 || (*utils.StartBlockId > 0 && blockId > *utils.StartBlockId) { // парсинг блока parser.BinaryData = blockBin if first { parser.CurrentVersion = consts.VERSION first = false } err = parser.ParseDataFull() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } file.Close() continue BEGIN } err = parser.InsertIntoBlockchain() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } file.Close() continue BEGIN } // отметимся, чтобы не спровоцировать очистку таблиц err = parser.UpdMainLock() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } file.Close() continue BEGIN } if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } file.Close() continue BEGIN } } // ненужный тут размер в конце блока данных data = make([]byte, 5) file.Read(data) } else { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // utils.Sleep(1) } file.Close() } else { newBlock, err := static.Asset("static/1block.bin") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } parser.BinaryData = newBlock parser.CurrentVersion = consts.VERSION err = parser.ParseDataFull() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } err = parser.InsertIntoBlockchain() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } utils.Sleep(1) d.dbUnlock() continue BEGIN } d.dbUnlock() err = d.ExecSql(`UPDATE config SET current_load_blockchain = 'nodes'`) if err != nil { if d.unlockPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } myConfig, err := d.OneRow("SELECT local_gate_ip, static_node_user_id FROM config").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } var hosts []map[string]string var nodeHost string var dataTypeMaxBlockId, dataTypeBlockBody int64 if len(myConfig["local_gate_ip"]) > 0 { hosts = append(hosts, map[string]string{"host": myConfig["local_gate_ip"], "user_id": myConfig["static_node_user_id"]}) nodeHost, err = d.Single("SELECT tcp_host FROM miners_data WHERE user_id = ?", myConfig["static_node_user_id"]).String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } dataTypeMaxBlockId = 9 dataTypeBlockBody = 8 //getBlockScriptName = "ajax?controllerName=protectedGetBlock"; //addNodeHost = "&nodeHost="+nodeHost; } else { // получим список нодов, с кем установлено рукопожатие hosts, err = d.GetAll("SELECT * FROM nodes_connection", -1) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } dataTypeMaxBlockId = 10 dataTypeBlockBody = 7 //getBlockScriptName = "ajax?controllerName=getBlock"; //addNodeHost = ""; } log.Info("%v", hosts) if len(hosts) == 0 { if d.dPrintSleep(err, 1) { break BEGIN } continue } maxBlockId := int64(1) maxBlockIdHost := "" var maxBlockIdUserId int64 // получим максимальный номер блока for i := 0; i < len(hosts); i++ { if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } conn, err := utils.TcpConn(hosts[i]["host"]) if err != nil { if d.dPrintSleep(err, 1) { break BEGIN } continue } // шлем тип данных _, err = conn.Write(utils.DecToBin(dataTypeMaxBlockId, 1)) if err != nil { conn.Close() if d.dPrintSleep(err, 1) { break BEGIN } continue } if len(nodeHost) > 0 { // защищенный режим err = utils.WriteSizeAndData([]byte(nodeHost), conn) if err != nil { conn.Close() if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } } // в ответ получаем номер блока blockIdBin := make([]byte, 4) _, err = conn.Read(blockIdBin) if err != nil { conn.Close() if d.dPrintSleep(err, 1) { break BEGIN } continue } conn.Close() id := utils.BinToDec(blockIdBin) if id > maxBlockId || i == 0 { maxBlockId = id maxBlockIdHost = hosts[i]["host"] maxBlockIdUserId = utils.StrToInt64(hosts[i]["user_id"]) } if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { utils.Sleep(1) break BEGIN } } // получим наш текущий имеющийся номер блока // ждем, пока разлочится и лочим сами, чтобы не попасть в тот момент, когда данные из блока уже занесены в БД, а info_block еще не успел обновиться err, restart = d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } currentBlockId, err = d.Single("SELECT block_id FROM info_block").Int64() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } log.Info("currentBlockId", currentBlockId, "maxBlockId", maxBlockId) if maxBlockId <= currentBlockId { if d.unlockPrintSleep(utils.ErrInfo(errors.New("maxBlockId <= currentBlockId")), d.sleepTime) { break BEGIN } continue } fmt.Printf("\nnode: %s\n", maxBlockIdHost) // в цикле собираем блоки, пока не дойдем до максимального for blockId := currentBlockId + 1; blockId < maxBlockId+1; blockId++ { d.UpdMainLock() if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } break BEGIN } variables, err := d.GetAllVariables() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // качаем тело блока с хоста maxBlockIdHost binaryBlock, err := utils.GetBlockBody(maxBlockIdHost, blockId, dataTypeBlockBody, nodeHost) if len(binaryBlock) == 0 { // баним на 1 час хост, который дал нам пустой блок, хотя должен был дать все до максимального // для тестов убрал, потом вставить. //nodes_ban ($db, $max_block_id_user_id, substr($binary_block, 0, 512)."\n".__FILE__.', '.__LINE__.', '. __FUNCTION__.', '.__CLASS__.', '. __METHOD__); //p.NodesBan(maxBlockIdUserId, "len(binaryBlock) == 0") if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } binaryBlockFull := binaryBlock utils.BytesShift(&binaryBlock, 1) // уберем 1-й байт - тип (блок/тр-я) // распарсим заголовок блока blockData := utils.ParseBlockHeader(&binaryBlock) log.Info("blockData: %v, blockId: %v", blockData, blockId) // если существуют глючная цепочка, тот тут мы её проигнорируем badBlocks_, err := d.Single("SELECT bad_blocks FROM config").Bytes() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } badBlocks := make(map[int64]string) if len(badBlocks_) > 0 { err = json.Unmarshal(badBlocks_, &badBlocks) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } if badBlocks[blockData.BlockId] == string(utils.BinToHex(blockData.Sign)) { d.NodesBan(maxBlockIdUserId, fmt.Sprintf("bad_block = %v => %v", blockData.BlockId, badBlocks[blockData.BlockId])) if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // размер блока не может быть более чем max_block_size if currentBlockId > 1 { if int64(len(binaryBlock)) > variables.Int64["max_block_size"] { d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`len(binaryBlock) > variables.Int64["max_block_size"] %v > %v`, len(binaryBlock), variables.Int64["max_block_size"])) if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } if blockData.BlockId != blockId { d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`blockData.BlockId != blockId %v > %v`, blockData.BlockId, blockId)) if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // нам нужен хэш предыдущего блока, чтобы проверить подпись prevBlockHash := "" if blockId > 1 { prevBlockHash, err = d.Single("SELECT hash FROM block_chain WHERE id = ?", blockId-1).String() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } prevBlockHash = string(utils.BinToHex([]byte(prevBlockHash))) } else { prevBlockHash = "0" } first := false if blockId == 1 { first = true } // нам нужен меркель-рут текущего блока mrklRoot, err := utils.GetMrklroot(binaryBlock, variables, first) if err != nil { d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`%v`, err)) if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // публичный ключ того, кто этот блок сгенерил nodePublicKey, err := d.GetNodePublicKey(blockData.UserId) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // SIGN от 128 байта до 512 байт. Подпись от TYPE, BLOCK_ID, PREV_BLOCK_HASH, TIME, USER_ID, LEVEL, MRKL_ROOT forSign := fmt.Sprintf("0,%v,%v,%v,%v,%v,%s", blockData.BlockId, prevBlockHash, blockData.Time, blockData.UserId, blockData.Level, mrklRoot) // проверяем подпись if !first { _, err = utils.CheckSign([][]byte{nodePublicKey}, forSign, blockData.Sign, true) } // качаем предыдущие блоки до тех пор, пока отличается хэш предыдущего. // другими словами, пока подпись с prevBlockHash будет неверной, т.е. пока что-то есть в $error if err != nil { log.Error("%v", utils.ErrInfo(err)) if blockId < 1 { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // нужно привести данные в нашей БД в соответствие с данными у того, у кого качаем более свежий блок //func (p *Parser) GetOldBlocks (userId, blockId int64, host string, hostUserId int64, goroutineName, getBlockScriptName, addNodeHost string) error { err := parser.GetOldBlocks(blockData.UserId, blockId-1, maxBlockIdHost, maxBlockIdUserId, GoroutineName, dataTypeBlockBody, nodeHost) if err != nil { log.Error("%v", err) d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`blockId: %v / %v`, blockId, err)) if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } else { log.Info("plug found blockId=%v\n", blockId) // получим наши транзакции в 1 бинарнике, просто для удобства var transactions []byte utils.WriteSelectiveLog("SELECT data FROM transactions WHERE verified = 1 AND used = 0") rows, err := d.Query("SELECT data FROM transactions WHERE verified = 1 AND used = 0") if err != nil { utils.WriteSelectiveLog(err) if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var data []byte err = rows.Scan(&data) utils.WriteSelectiveLog(utils.BinToHex(data)) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } transactions = append(transactions, utils.EncodeLengthPlusData(data)...) } rows.Close() if len(transactions) > 0 { // отмечаем, что эти тр-ии теперь нужно проверять по новой utils.WriteSelectiveLog("UPDATE transactions SET verified = 0 WHERE verified = 1 AND used = 0") affect, err := d.ExecSqlGetAffect("UPDATE transactions SET verified = 0 WHERE verified = 1 AND used = 0") if err != nil { utils.WriteSelectiveLog(err) if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect)) // откатываем по фронту все свежие тр-ии parser.BinaryData = transactions err = parser.ParseDataRollbackFront(false) if err != nil { utils.Sleep(1) continue BEGIN } } err = parser.RollbackTransactionsTestblock(true) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("DELETE FROM testblock") if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } // теперь у нас в таблицах всё тоже самое, что у нода, у которого качаем блок // и можем этот блок проверить и занести в нашу БД parser.BinaryData = binaryBlockFull err = parser.ParseDataFull() if err == nil { err = parser.InsertIntoBlockchain() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } // начинаем всё с начала уже с другими нодами. Но у нас уже могут быть новые блоки до $block_id, взятые от нода, которого с в итоге мы баним if err != nil { d.NodesBan(maxBlockIdUserId, fmt.Sprintf(`blockId: %v / %v`, blockId, err)) if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
/* * просто шлем всем, кто есть в nodes_connection хэши блока и тр-ий * если мы не майнер, то шлем всю тр-ию целиком, блоки слать не можем * если майнер - то шлем только хэши, т.к. у нас есть хост, откуда всё можно скачать * */ func Disseminator(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "Disseminator" d := new(daemon) d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } d.goRoutineName = GoroutineName d.chAnswer = chAnswer d.chBreaker = chBreaker if utils.Mobile() { d.sleepTime = 300 } else { d.sleepTime = 1 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } var hosts []map[string]string var nodeData map[string]string nodeConfig, err := d.GetNodeConfig() if len(nodeConfig["local_gate_ip"]) == 0 { // обычный режим hosts, err = d.GetAll(` SELECT miners_data.user_id, miners_data.tcp_host as host, node_public_key FROM nodes_connection LEFT JOIN miners_data ON nodes_connection.user_id = miners_data.user_id `, -1) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } if len(hosts) == 0 { if d.dSleep(d.sleepTime) { break BEGIN } log.Debug("len(hosts) == 0") continue } } else { // защищенный режим nodeData, err = d.OneRow("SELECT node_public_key, tcp_host FROM miners_data WHERE user_id = ?", nodeConfig["static_node_user_id"]).String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } hosts = append(hosts, map[string]string{"host": nodeConfig["local_gate_ip"], "node_public_key": nodeData["node_public_key"], "user_id": nodeConfig["static_node_user_id"]}) } myUsersIds, err := d.GetMyUsersIds(false, false) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } myMinersIds, err := d.GetMyMinersIds(myUsersIds) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } log.Debug("%v", myUsersIds) log.Debug("%v", myMinersIds) // если среди тр-ий есть смена нодовского ключа, то слать через отправку хэшей с последющей отдачей данных может не получиться // т.к. при некорректном нодовском ключе придет зашифрованый запрос на отдачу данных, а мы его не сможем расшифровать т.к. ключ у нас неверный var changeNodeKey int64 if len(myUsersIds) > 0 { changeNodeKey, err = d.Single(` SELECT count(*) FROM transactions WHERE type = ? AND user_id IN (`+strings.Join(utils.SliceInt64ToString(myUsersIds), ",")+`) `, utils.TypeInt("ChangeNodeKey")).Int64() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } var dataType int64 // это тип для того, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные // если я майнер и работаю в обычном режиме, то должен слать хэши if len(myMinersIds) > 0 && len(nodeConfig["local_gate_ip"]) == 0 && changeNodeKey == 0 { log.Debug("0") dataType = 1 // определим, от кого будем слать r := utils.RandInt(0, len(myMinersIds)) myMinerId := myMinersIds[r] myUserId, err := d.Single("SELECT user_id FROM miners_data WHERE miner_id = ?", myMinerId).Int64() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // возьмем хэш текущего блока и номер блока // для теста ролбеков отключим на время data, err := d.OneRow("SELECT block_id, hash, head_hash FROM info_block WHERE sent = 0").Bytes() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("UPDATE info_block SET sent = 1") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } /* * Составляем данные на отправку * */ // 5 байт = наш user_id. Но они будут не первые, т.к. m_curl допишет вперед user_id получателя (нужно для пулов) toBeSent := utils.DecToBin(myUserId, 5) if len(data) > 0 { // блок // если 5-й байт = 0, то на приемнике будем читать блок, если = 1 , то сразу хэши тр-ий toBeSent = append(toBeSent, utils.DecToBin(0, 1)...) toBeSent = append(toBeSent, utils.DecToBin(utils.BytesToInt64(data["block_id"]), 3)...) toBeSent = append(toBeSent, data["hash"]...) toBeSent = append(toBeSent, data["head_hash"]...) err = d.ExecSql("UPDATE info_block SET sent = 1") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } else { // тр-ии без блока toBeSent = append(toBeSent, utils.DecToBin(1, 1)...) } // возьмем хэши тр-ий //utils.WriteSelectiveLog("SELECT hash, high_rate FROM transactions WHERE sent = 0 AND for_self_use = 0") transactions, err := d.GetAll("SELECT hash, high_rate FROM transactions WHERE sent = 0 AND for_self_use = 0", -1) if err != nil { utils.WriteSelectiveLog(err) if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // нет ни транзакций, ни блока для отправки... if len(transactions) == 0 && len(toBeSent) < 10 { //utils.WriteSelectiveLog("len(transactions) == 0") //log.Debug("len(transactions) == 0") if d.dSleep(d.sleepTime) { break BEGIN } log.Debug("len(transactions) == 0 && len(toBeSent) == 0") continue BEGIN } for _, data := range transactions { hexHash := utils.BinToHex([]byte(data["hash"])) toBeSent = append(toBeSent, utils.DecToBin(utils.StrToInt64(data["high_rate"]), 1)...) toBeSent = append(toBeSent, []byte(data["hash"])...) utils.WriteSelectiveLog("UPDATE transactions SET sent = 1 WHERE hex(hash) = " + string(hexHash)) affect, err := d.ExecSqlGetAffect("UPDATE transactions SET sent = 1 WHERE hex(hash) = ?", hexHash) if err != nil { utils.WriteSelectiveLog(err) if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect)) } // отправляем блок и хэши тр-ий, если есть что отправлять if len(toBeSent) > 0 { for _, host := range hosts { go d.DisseminatorType1(host["host"], utils.StrToInt64(host["user_id"]), host["node_public_key"], toBeSent, dataType) } } } else { log.Debug("1") var remoteNodeHost string // если просто юзер или работаю в защищенном режиме, то шлю тр-ии целиком. слать блоки не имею права. if len(nodeConfig["local_gate_ip"]) > 0 { dataType = 3 remoteNodeHost = nodeData["host"] } else { dataType = 2 remoteNodeHost = "" } log.Debug("dataType: %d", dataType) var toBeSent []byte // сюда пишем все тр-ии, которые будем слать другим нодам // возьмем хэши и сами тр-ии utils.WriteSelectiveLog("SELECT hash, data FROM transactions WHERE sent = 0") rows, err := d.Query("SELECT hash, data FROM transactions WHERE sent = 0") if err != nil { utils.WriteSelectiveLog(err) if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var hash, data []byte err = rows.Scan(&hash, &data) if err != nil { rows.Close() if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("hash %x", hash) hashHex := utils.BinToHex(hash) utils.WriteSelectiveLog("UPDATE transactions SET sent = 1 WHERE hex(hash) = " + string(hashHex)) affect, err := d.ExecSqlGetAffect("UPDATE transactions SET sent = 1 WHERE hex(hash) = ?", hashHex) if err != nil { utils.WriteSelectiveLog(err) rows.Close() if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect)) toBeSent = append(toBeSent, data...) } rows.Close() // шлем тр-ии if len(toBeSent) > 0 { for _, host := range hosts { userId := utils.StrToInt64(host["user_id"]) go func(host string, userId int64, node_public_key string) { log.Debug("host %v / userId %v", host, userId) conn, err := utils.TcpConn(host) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } defer conn.Close() randTestblockHash, err := d.Single("SELECT head_hash FROM queue_testblock").String() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // получаем IV + ключ + зашифрованный текст encryptedData, _, _, err := utils.EncryptData(toBeSent, []byte(node_public_key), randTestblockHash) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // вначале шлем тип данных, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные _, err = conn.Write(utils.DecToBin(dataType, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // т.к. на приеме может быть пул, то нужно дописать в начало user_id, чьим нодовским ключем шифруем /*_, err = conn.Write(utils.DecToBin(userId, 5)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return }*/ encryptedData = append(utils.DecToBin(userId, 5), encryptedData...) // это может быть защищенное локальное соедниение (dataType = 3) и принимающему ноду нужно знать, куда дальше слать данные и чьим они зашифрованы ключем if len(remoteNodeHost) > 0 { /* _, err = conn.Write([]byte(remoteNodeHost)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return }*/ encryptedData = append([]byte(remoteNodeHost), encryptedData...) } log.Debug("encryptedData %x", encryptedData) // в 4-х байтах пишем размер данных, которые пошлем далее size := utils.DecToBin(len(encryptedData), 4) _, err = conn.Write(size) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // далее шлем сами данные _, err = conn.Write(encryptedData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } }(host["host"], userId, host["node_public_key"]) } } } d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func MaxOtherCurrenciesGenerator(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "MaxOtherCurrenciesGenerator" d := new(daemon) d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } d.goRoutineName = GoroutineName d.chAnswer = chAnswer d.chBreaker = chBreaker if utils.Mobile() { d.sleepTime = 3600 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } err = d.notMinerSetSleepTime(1800) if err != nil { log.Error("%v", err) return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } blockId, err := d.GetBlockId() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if blockId == 0 { if d.unlockPrintSleep(utils.ErrInfo("blockId == 0"), d.sleepTime) { break BEGIN } continue BEGIN } _, _, myMinerId, _, _, _, err := d.TestBlock() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // а майнер ли я ? if myMinerId == 0 { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } variables, err := d.GetAllVariables() curTime := utils.Time() totalCountCurrencies, err := d.GetCountCurrencies() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // проверим, прошло ли 2 недели с момента последнего обновления pctTime, err := d.Single("SELECT max(time) FROM max_other_currencies_time").Int64() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if curTime-pctTime <= variables.Int64["new_max_other_currencies"] { if d.unlockPrintSleep(utils.ErrInfo("14 day error"), d.sleepTime) { break BEGIN } continue BEGIN } // берем все голоса maxOtherCurrenciesVotes := make(map[int64][]map[int64]int64) rows, err := d.Query("SELECT currency_id, count, count(user_id) as votes FROM votes_max_other_currencies GROUP BY currency_id, count ORDER BY currency_id, count ASC") if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var currency_id, count, votes int64 err = rows.Scan(¤cy_id, &count, &votes) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } maxOtherCurrenciesVotes[currency_id] = append(maxOtherCurrenciesVotes[currency_id], map[int64]int64{count: votes}) } rows.Close() newMaxOtherCurrenciesVotes := make(map[string]int64) for currencyId, countAndVotes := range maxOtherCurrenciesVotes { newMaxOtherCurrenciesVotes[utils.Int64ToStr(currencyId)] = utils.GetMaxVote(countAndVotes, 0, totalCountCurrencies, 10) } jsonData, err := json.Marshal(newMaxOtherCurrenciesVotes) _, myUserId, _, _, _, _, err := d.TestBlock() forSign := fmt.Sprintf("%v,%v,%v,%s", utils.TypeInt("NewMaxOtherCurrencies"), curTime, myUserId, jsonData) 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("NewMaxOtherCurrencies"), 1) data = append(data, utils.DecToBin(curTime, 4)...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(myUserId))...) data = append(data, utils.EncodeLengthPlusData(jsonData)...) data = append(data, utils.EncodeLengthPlusData([]byte(binSign))...) err = d.InsertReplaceTxInQueue(data) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } 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 Notifications(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "Notifications" d := new(daemon) d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } d.goRoutineName = GoroutineName d.chAnswer = chAnswer d.chBreaker = chBreaker if utils.Mobile() { d.sleepTime = 300 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } BEGIN: for { //sendnotif.SendMobileNotification("11111111", "222222222222222222") log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } // валюты currencyList, err := d.GetCurrencyList(false) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } notificationsArray := make(map[string]map[int64]map[string]string) userEmailSmsData := make(map[int64]map[string]string) myUsersIds, err := d.GetCommunityUsers() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } var community bool if len(myUsersIds) == 0 { community = false myUserId, err := d.GetMyUserId("") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } myUsersIds = append(myUsersIds, myUserId) } else { community = true } /*myPrefix, err:= d.GetMyPrefix() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN }*/ myBlockId, err := d.GetMyBlockId() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } blockId, err := d.GetBlockId() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if myBlockId > blockId { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(myUsersIds) > 0 { for i := 0; i < len(myUsersIds); i++ { myPrefix := "" if community { myPrefix = utils.Int64ToStr(myUsersIds[i]) + "_" } myData, err := d.OneRow("SELECT * FROM " + myPrefix + "my_table").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // на пуле шлем уведомления только майнерам if community && myData["miner_id"] == "0" { continue } myNotifications, err := d.GetAll("SELECT * FROM "+myPrefix+"my_notifications", -1) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for _, data := range myNotifications { notificationsArray[data["name"]] = make(map[int64]map[string]string) notificationsArray[data["name"]][myUsersIds[i]] = map[string]string{"email": data["email"], "sms": data["sms"], "mobile": data["mobile"]} userEmailSmsData[myUsersIds[i]] = myData } } } poolAdminUserId, err := d.GetPoolAdminUserId() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } subj := "DCoin notifications" for name, notificationInfo := range notificationsArray { switch name { case "admin_messages": data, err := d.OneRow("SELECT id, message FROM alert_messages WHERE notification = 0").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(data) > 0 { err = d.ExecSql("UPDATE alert_messages SET notification = 1 WHERE id = ?", data["id"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if myBlockId > blockId { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for userId, emailSms := range notificationInfo { if emailSms["mobile"] == "1" { sendnotif.SendMobileNotification(subj, userEmailSmsData[userId]["text"]) } if emailSms["email"] == "1" { err = d.SendMail("From Admin: "+data["message"], subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if emailSms["sms"] == "1" { _, err = utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], userEmailSmsData[userId]["text"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } } case "incoming_cash_requests": for i := 0; i < len(myUsersIds); i++ { myPrefix := "" if community { myPrefix = utils.Int64ToStr(myUsersIds[i]) + "_" } userId := myUsersIds[i] data, err := d.OneRow("SELECT id, amount, currency_id FROM "+myPrefix+"my_cash_requests WHERE to_user_id = ? AND notification = 0 AND status = 'pending'", userId).String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(data) > 0 { text := `You"ve got the request for ` + data["amount"] + ` ` + currencyList[utils.StrToInt64(data["currencyId"])] + `. It has to be repaid within the next 48 hours.` if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if notificationsArray[name][userId]["email"] == "1" { err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if notificationsArray[name][userId]["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } err = d.ExecSql("UPDATE "+myPrefix+"my_cash_requests SET notification = 1 WHERE id = ?", data["id"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } case "change_in_status": for i := 0; i < len(myUsersIds); i++ { myPrefix := "" if community { myPrefix = utils.Int64ToStr(myUsersIds[i]) + "_" } userId := myUsersIds[i] status, err := d.Single("SELECT status FROM " + myPrefix + "my_table WHERE notification_status = 0").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(status) > 0 { text := `New status: ` + status if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if notificationsArray[name][userId]["email"] == "1" { err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if notificationsArray[name][userId]["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } err = d.ExecSql("UPDATE " + myPrefix + "my_table SET notification_status = 1") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } case "dc_came_from": for i := 0; i < len(myUsersIds); i++ { myPrefix := "" if community { myPrefix = utils.Int64ToStr(myUsersIds[i]) + "_" } userId := myUsersIds[i] myDcTransactions, err := d.GetAll(` SELECT id, amount, currency_id, comment_status, comment FROM `+myPrefix+`my_dc_transactions WHERE to_user_id = ? AND notification = 0 AND status = 'approved'`, -1, userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for _, data := range myDcTransactions { comment := "" if data["comment_status"] == "decrypted" { comment = data["comment"] } text := `You've got ` + data["amount"] + ` D` + currencyList[utils.StrToInt64(data["currency_id"])] + ` ` + comment if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if notificationsArray[name][userId]["email"] == "1" { //err = d.SendMail(`<br><span style="font-size:16px">`+text+`</span>`, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if notificationsArray[name][userId]["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } err = d.ExecSql("UPDATE "+myPrefix+"my_dc_transactions SET notification = 1 WHERE id = ?", data["id"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } case "dc_sent": for i := 0; i < len(myUsersIds); i++ { myPrefix := "" if community { myPrefix = utils.Int64ToStr(myUsersIds[i]) + "_" } userId := myUsersIds[i] myDcTransactions, err := d.GetAll(` SELECT id, amount, currency_id FROM `+myPrefix+`my_dc_transactions WHERE to_user_id != ? AND notification = 0 AND status = 'approved'`, -1, userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for _, data := range myDcTransactions { text := `Debiting ` + data["amount"] + ` D` + currencyList[utils.StrToInt64(data["currency_id"])] if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if notificationsArray[name][userId]["email"] == "1" { err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if notificationsArray[name][userId]["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } err = d.ExecSql("UPDATE "+myPrefix+"my_dc_transactions SET notification = 1 WHERE id = ?", data["id"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } case "update_primary_key": for i := 0; i < len(myUsersIds); i++ { myPrefix := "" if community { myPrefix = utils.Int64ToStr(myUsersIds[i]) + "_" } userId := myUsersIds[i] data, err := d.OneRow("SELECT id FROM " + myPrefix + "my_keys WHERE notification = 0 AND status = 'approved'").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(data) > 0 { text := `Update primary key` if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if notificationsArray[name][userId]["email"] == "1" { err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if notificationsArray[name][userId]["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } err = d.ExecSql("UPDATE "+myPrefix+"my_keys SET notification = 1 WHERE id = ?", data["id"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } case "update_email": for i := 0; i < len(myUsersIds); i++ { myPrefix := "" if community { myPrefix = utils.Int64ToStr(myUsersIds[i]) + "_" } userId := myUsersIds[i] myNewEmail, err := d.Single("SELECT status FROM " + myPrefix + "my_table WHERE notification_email = 0").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(myNewEmail) > 0 { text := `New email: ` + myNewEmail if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if notificationsArray[name][userId]["email"] == "1" { err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if notificationsArray[name][userId]["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } err = d.ExecSql("UPDATE " + myPrefix + "my_table SET notification_email = 1") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } case "update_sms_request": for i := 0; i < len(myUsersIds); i++ { myPrefix := "" if community { myPrefix = utils.Int64ToStr(myUsersIds[i]) + "_" } userId := myUsersIds[i] smsHttpGetRequest, err := d.Single("SELECT sms_http_get_request FROM " + myPrefix + "my_table WHERE notification_sms_http_get_request = 0").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(smsHttpGetRequest) > 0 { text := `New sms_http_get_request ` + smsHttpGetRequest if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if notificationsArray[name][userId]["email"] == "1" { err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if notificationsArray[name][userId]["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } err = d.ExecSql("UPDATE " + myPrefix + "my_table SET notification_sms_http_get_request = 1") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } case "voting_results": myDcTransactions, err := d.GetAll(` SELECT id, currency_id, miner, user, block_id FROM pct WHERE notification = 0`, -1) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } text := "" pctUpd := false for _, data := range myDcTransactions { pctUpd = true text += fmt.Sprintf("New pct %v! miner: %v %/block, user: %v %/block", currencyList[utils.StrToInt64(data["currency_id"])], ((math.Pow(1+utils.StrToFloat64(data["miner"]), 120) - 1) * 100), ((math.Pow(1+utils.StrToFloat64(data["user"]), 120) - 1) * 100)) } if pctUpd { err = d.ExecSql("UPDATE pct SET notification = 1 WHERE notification = 0") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if myBlockId > blockId { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // шлется что-то не то, потом поправлю, пока отключил if community { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(text) > 0 { for userId, emailSms := range notificationInfo { if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if emailSms["email"] == "1" { err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if emailSms["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } } } case "voting_time": // Прошло 2 недели с момента Вашего голосования за % for i := 0; i < len(myUsersIds); i++ { myPrefix := "" if community { myPrefix = utils.Int64ToStr(myUsersIds[i]) + "_" } userId := myUsersIds[i] lastVoting, err := d.Single("SELECT last_voting FROM " + myPrefix + "my_complex_votes WHERE notification = 0").Int64() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if lastVoting > 0 && utils.Time()-lastVoting > 86400*14 { text := "It's 2 weeks from the moment you voted." if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if notificationsArray[name][userId]["email"] == "1" { err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if notificationsArray[name][userId]["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } err = d.ExecSql("UPDATE " + myPrefix + "my_complex_votes SET notification = 1") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } } case "new_version": newVersion, err := d.Single("SELECT version FROM new_version WHERE notification = 0 AND alert = 1").String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("UPDATE new_version SET notification = 1 WHERE version = ?", newVersion) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if myBlockId > blockId { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // в пуле это лишняя инфа if community { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if len(newVersion) > 0 { for userId, emailSms := range notificationInfo { text := "New version: " + newVersion if notificationsArray[name][userId]["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if emailSms["email"] == "1" { err = d.SendMail(text, subj, userEmailSmsData[userId]["email"], userEmailSmsData[userId], community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if emailSms["sms"] == "1" { utils.SendSms(userEmailSmsData[userId]["sms_http_get_request"], text) } } } case "node_time": // Расхождение времени сервера более чем на 5 сек var adminUserId int64 // если работаем в режиме пула, то нужно слать инфу админу пула if community { adminUserId = poolAdminUserId } else { // проверим, нода ли мы my_table, err := d.OneRow("SELECT user_id, miner_id FROM my_table").Int64() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } if my_table["miner_id"] == 0 { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } else { adminUserId = my_table["user_id"] } emailSms := notificationInfo[adminUserId] myData := userEmailSmsData[adminUserId] if len(myData) > 0 { networkTime, err := utils.GetNetworkTime() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } diff := int64(math.Abs(float64(utils.Time() - networkTime.Unix()))) text := "" if diff > 5 { text = "Divergence time " + utils.Int64ToStr(diff) + " sec" } if emailSms["mobile"] == "1" { sendnotif.SendMobileNotification(subj, text) } if emailSms["email"] == "1" { err = d.SendMail(text, subj, myData["email"], myData, community, poolAdminUserId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if emailSms["sms"] == "1" { utils.SendSms(myData["sms_http_get_request"], text) } } } } } if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }