func (c *Controller) BlockExplorer() (string, error) { var err error blockId := int64(utils.StrToFloat64(c.Parameters["blockId"])) start := int64(utils.StrToFloat64(c.Parameters["start"])) var data, sql string if start > 0 || (start == 0 && blockId == 0) { if start == 0 && blockId == 0 { data += "<h3>Latest Blocks</h3>" sql = ` SELECT data, hash FROM block_chain ORDER BY id DESC LIMIT 15` } else { sql = ` SELECT data, hash FROM block_chain ORDER BY id ASC LIMIT ` + utils.Int64ToStr(start-1) + `, 100` } data += `<table class="table"><tr><th>Block</th><th>Hash</th><th>Time</th><th><nobr>User id</nobr></th><th><nobr>Miner id</nobr></th><th>Level</th><th>Transactions</th></tr>` blocksChain, err := c.GetAll(sql, -1) if err != nil { return "", utils.ErrInfo(err) } for _, blockData := range blocksChain { hash := utils.BinToHex([]byte(blockData["hash"])) binaryData := []byte(blockData["data"]) parser := new(dcparser.Parser) parser.DCDB = c.DCDB parser.BinaryData = binaryData err = parser.ParseDataLite() parser.BlockData.Sign = utils.BinToHex(parser.BlockData.Sign) minerId, err := c.GetMinerId(parser.BlockData.UserId) if err != nil { return "", utils.ErrInfo(err) } data += fmt.Sprintf(`<tr><td><a href="#" onclick="dc_navigate('blockExplorer', {'blockId':%d})">%d</a></td><td>%s</td><td><nobr><span class='unixtime'>%d</span></nobr></td><td>%d</td><td>%d</td><td>%d</td><td>`, parser.BlockData.BlockId, parser.BlockData.BlockId, hash, parser.BlockData.Time, parser.BlockData.UserId, minerId, parser.BlockData.Level) data += utils.IntToStr(len(parser.TxMapArr)) data += "</td></tr>" } data += "</table>" } else if blockId > 0 { data += `<table class="table">` blockChain, err := c.OneRow("SELECT data, hash, cur_0l_miner_id, max_miner_id FROM block_chain WHERE id = ?", blockId).String() if err != nil { return "", utils.ErrInfo(err) } binToHexArray := []string{"sign", "public_key", "encrypted_message", "comment", "bin_public_keys"} hash := utils.BinToHex([]byte(blockChain["hash"])) binaryData := blockChain["data"] parser := new(dcparser.Parser) parser.DCDB = c.DCDB parser.BinaryData = []byte(binaryData) err = parser.ParseDataLite() if err != nil { return "", utils.ErrInfo(err) } parser.BlockData.Sign = utils.BinToHex(parser.BlockData.Sign) previous := parser.BlockData.BlockId - 1 next := parser.BlockData.BlockId + 1 levelsRange := utils.GetBlockGeneratorMinerIdRange(utils.StrToInt64(blockChain["cur_0l_miner_id"]), utils.StrToInt64(blockChain["max_miner_id"])) minerId, err := c.GetMinerId(parser.BlockData.UserId) if err != nil { return "", utils.ErrInfo(err) } _, _, _, CurrentUserId, _, _, _ := c.TestBlock() maxMinerId, err := c.Single("SELECT max(miner_id) FROM miners").Int64() if err != nil { return "", utils.ErrInfo(err) } currentMinerId, err := c.Single("SELECT miner_id FROM miners_data WHERE user_id = ?", CurrentUserId).Int64() if err != nil { return "", utils.ErrInfo(err) } NextBlockLevelsRange := utils.GetBlockGeneratorMinerIdRange(currentMinerId, maxMinerId) data += fmt.Sprintf(`<tr><td><strong>Raw data</strong></td><td><a href='ajax?controllerName=getBlock&id=%d&download=1' target='_blank'>Download</a></td></tr>`, parser.BlockData.BlockId) data += fmt.Sprintf(`<tr><td><strong>Block_id</strong></td><td>%d (<a href="#" onclick="dc_navigate('blockExplorer', {'blockId':%d})">Previous</a> / <a href="#" onclick="dc_navigate('blockExplorer', {'blockId':%d})">Next</a> )</td></tr>`, parser.BlockData.BlockId, previous, next) data += fmt.Sprintf(`<tr><td><strong>Hash</strong></td><td>%s</td></tr>`, hash) data += fmt.Sprintf(`<tr><td><strong>Time</strong></td><td><span class='unixtime'>%d</span> / %d</td></tr>`, parser.BlockData.Time, parser.BlockData.Time) data += fmt.Sprintf(`<tr><td><strong>User_id</strong></td><td>%d</td></tr>`, parser.BlockData.UserId) data += fmt.Sprintf(`<tr><td><strong>Miner_Id</strong></td><td>%d</td></tr>`, minerId) data += fmt.Sprintf(`<tr><td><strong>Level</strong></td><td>%d (%v) next: %v</td></tr>`, parser.BlockData.Level, levelsRange, NextBlockLevelsRange) data += fmt.Sprintf(`<tr><td><strong>Sign</strong></td><td>%s</td></tr>`, parser.BlockData.Sign) if len(parser.TxMapArr) > 0 { data += `<tr><td><strong>Transactions</strong></td><td><div><pre style='width: 700px'>` for i := 0; i < len(parser.TxMapArr); i++ { for k, data_ := range parser.TxMapArr[i] { if utils.InSliceString(k, binToHexArray) { parser.TxMapArr[i][k] = utils.BinToHex(data_) } if k == "file" { parser.TxMapArr[i][k] = []byte("file size: " + utils.IntToStr(len(data_))) } else if k == "code" { parser.TxMapArr[i][k] = utils.DSha256(data_) } else if k == "secret" { parser.TxMapArr[i][k] = utils.BinToHex(data_) } data += fmt.Sprintf("%v : %s\n", k, parser.TxMapArr[i][k]) } data += "\n\n" } data += "</pre></div></td></tr>" } data += "</table>" } // пока панель тут myNotice := make(map[string]string) if c.SessUserId > 0 { myNotice, err = c.GetMyNoticeData(c.SessUserId, c.SessUserId, c.MyPrefix, c.Lang) if err != nil { return "", utils.ErrInfo(err) } } TemplateStr, err := makeTemplate("block_explorer", "blockExplorer", &BlockExplorerPage{ Lang: c.Lang, CurrencyList: c.CurrencyListCf, MyNotice: myNotice, Data: data, Start: start, BlockId: blockId, PoolAdmin: c.PoolAdmin, SessRestricted: c.SessRestricted, UserId: c.SessUserId}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func 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 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) }