func check(host string, userId int64) *answerType { /*tcpAddr, err := net.ResolveTCPAddr("tcp", host) if err != nil { log.Error("%v", utils.ErrInfo(err)) return &answerType{userId: userId, answer: 0} } conn, err := net.DialTCP("tcp", nil, tcpAddr)*/ conn, err := net.DialTimeout("tcp", host, 5*time.Second) if err != nil { log.Debug("%v", utils.ErrInfo(err)) return &answerType{userId: userId, answer: 0} } defer conn.Close() conn.SetReadDeadline(time.Now().Add(consts.READ_TIMEOUT * time.Second)) conn.SetWriteDeadline(time.Now().Add(consts.WRITE_TIMEOUT * time.Second)) // вначале шлем тип данных, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные _, err = conn.Write(utils.DecToBin(5, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return &answerType{userId: userId, answer: 0} } // в 5-и байтах пишем userID, чтобы проверить, верный ли у него нодовский ключ, т.к. иначе ему нельзя слать зашифрованные данные _, err = conn.Write(utils.DecToBin(userId, 5)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return &answerType{userId: userId, answer: 0} } // ответ всегда 1 байт. 0 или 1 answer := make([]byte, 1) _, err = conn.Read(answer) if err != nil { log.Error("%v", utils.ErrInfo(err)) return &answerType{userId: userId, answer: 0} } // создадим канал для чата if utils.BinToDec(answer) == 1 { } log.Debug("host: %v / answer: %v / userId: %v", host, answer, userId) return &answerType{userId: userId, answer: utils.BinToDec(answer)} }
func (t *TcpServer) Type9() { /* Делаем запрос на указанную ноду, чтобы получить оттуда номер макс. блока * запрос шлет демон blocksCollection */ // размер данных buf := make([]byte, 4) _, err := t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } size := utils.BinToDec(buf) if size < 10485760 { // сами данные binaryData := make([]byte, size) /*_, err = t.Conn.Read(binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return }*/ //binaryData, err = ioutil.ReadAll(t.Conn) _, err = io.ReadFull(t.Conn, binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } //blockId := utils.BinToDecBytesShift(&binaryData, 4) host, err := utils.ProtectedCheckRemoteAddrAndGetHost(&binaryData, t.Conn) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // шлем данные указанному хосту conn2, err := utils.TcpConn(host) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } defer conn2.Close() // шлем тип данных _, err = conn2.Write(utils.DecToBin(10, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // в ответ получаем номер блока blockIdBin := make([]byte, 4) _, err = conn2.Read(blockIdBin) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // и возвращаем номер блока демону, который этот запрос прислал _, err = t.Conn.Write(blockIdBin) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } }
func checkConf(host string, blockId int64) string { log.Debug("host: %v", host) /*tcpAddr, err := net.ResolveTCPAddr("tcp", host) if err != nil { log.Error("%v", utils.ErrInfo(err)) return "0" } conn, err := net.DialTCP("tcp", nil, tcpAddr)*/ conn, err := net.DialTimeout("tcp", host, 5*time.Second) if err != nil { log.Error("%v", utils.ErrInfo(err)) return "0" } defer conn.Close() conn.SetReadDeadline(time.Now().Add(consts.READ_TIMEOUT * time.Second)) conn.SetWriteDeadline(time.Now().Add(consts.WRITE_TIMEOUT * time.Second)) // вначале шлем тип данных, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные _, err = conn.Write(utils.DecToBin(4, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return "0" } // в 4-х байтах пишем ID блока, хэш которого хотим получить size := utils.DecToBin(blockId, 4) _, err = conn.Write(size) if err != nil { log.Error("%v", utils.ErrInfo(err)) return "0" } // ответ всегда 32 байта hash := make([]byte, 32) _, err = conn.Read(hash) if err != nil { log.Error("%v", utils.ErrInfo(err)) return "0" } return string(hash) }
func TestDisseminator(t *testing.T) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() dir, err := filepath.Abs(filepath.Dir(os.Args[0])) if err != nil { t.Error(err) } fmt.Println(dir) /*configIni_, err := config.NewConfig("ini", "/home/z/IdeaProjects/src/github.com/c-darwin/dcoin-go/config.ini") if err != nil { t.Error("%v", utils.ErrInfo(err)) } configIni, err := configIni_.GetSection("default") if err != nil { t.Error("%v", utils.ErrInfo(err)) }*/ host := "pool.dcoin.club:8088" userId := int64(2) myUserId := int64(4) nodePublicKey := utils.HexToBin([]byte("30820122300d06092a864886f70d01010105000382010f003082010a0282010100b85bf8eb06d70e9f28961725ec04957d9c42db127bb788623b5063b7152bdf0df9f1af08a3cdb89f354fe86c43f9f071614b75ccee04ee9e61c749f1800870ad0ada6fc9dbcb928b2049376a06ac6754f6d2832a865e2e4bcfbd1451deb6d2c1ce6a0000701bdce2ec5c20da33ea427a58e9d9bd2807e0c712676593231410b6b0a35b392693cd62e33378987db36b4549ef5f65b172afd7cca9daed6d23e5239d966de9f31a83df4b59cb67ac5c1a816ee633cfcd3a87897b6a9053f3bd4131a403e4a20f301eea5efd31803cdf468663a605cdea96cf6b1cb698b7bb38ab5feb93b68972589d22b910520aab3b20575f2d0bc28b4960b8f912f5b15cede0af0203010001")) tx := utils.HexToBin([]byte("0c55b20550013401320131013204302e3031013001300130013001300130013001300130013082010096a9486eb64fd6ca5992e96e879e60881941d7c7bc62a0b86d60d5662b3023e1b8206105cd605791019d01ebc4c0b843284ab58efb772a159066f5a635b94c4344f09f640f244d8f68264cc1c9f83b2471547504041f8c16d8e2af77b07c5fa3799c40f267b1c7fc03326195737b3c605481e4ff37713931c28bc258a83963abf3222c287346b6ba872163b63a676ba9538f6d73fac5ee90500068541c07abddc77dff14eb3a18e47b4157228fe435c79cfa2a6189cef97fcc5f9fd58d1efa4c12f3de3db2f1993d4cd029cd3471f8a82341f75df61af247b70661ae8848afc18d28ab7654f67591f271d826f3925a4b7798653651f1e8c62854ef0bf97127f182010382010056ab8e00429fd794d2b0b64dce4cb0e36d34e59090379249990bcdc824251f907fca3e912a2e1e759dd5622b42aa86149740d72faf9743262875470b57c8c6a8333358a043ec9d8033f799578547bb04eb0f09c8e51898990f4f6760af5213ff61a95506f8b294b0ded892cfa9fcdb801887d1bb405f99ce3656818ce23de0a675cf190a5b616bea7c301f1a76e3dbbfb2c576580daf49e8f83e2286f0a62e869e49295f8bb07da0c25ac0b0a1fd3e7a82887c34f7fdda2112f334e19d7c68a130447536543752ef5a51c16ae456eaf0aadc28dbabcc27e13b7c50942704258e018f6cb898fc4a3c8a7018ee9e529b5f789973b941de7336ce7bf08b79cfeae7")) hash := utils.HexToBin(utils.Md5(tx)) toBeSent := utils.DecToBin(myUserId, 5) toBeSent = append(toBeSent, utils.DecToBin(1, 1)...) toBeSent = append(toBeSent, utils.DecToBin(utils.StrToInt64("0"), 1)...) toBeSent = append(toBeSent, []byte(hash)...) fmt.Printf("hash %x %v", hash, hash) dataType := int64(1) db := DbConnect(chBreaker, chAnswer, GoroutineName) DisseminatorType1(host, userId, string(nodePublicKey), db, toBeSent, dataType) }
func (t *TcpServer) Type10() { /* Выдаем номер макс. блока * запрос шлет демон blocksCollection */ blockId, err := t.Single("SELECT block_id FROM info_block").Int64() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } _, err = t.Conn.Write(utils.DecToBin(blockId, 4)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } }
func (t *TcpServer) Type3() { // размер данных buf := make([]byte, 4) _, err := t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } size := utils.BinToDec(buf) if size < 10485760 { // сами данные binaryData := make([]byte, size) //binaryData, err = ioutil.ReadAll(t.Conn) _, err = io.ReadFull(t.Conn, binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } /* * Пересылаем тр-ию, полученную по локальной сети, конечному ноду, указанному в первых 100 байтах тр-ии * от демона disseminator * */ host, err := utils.ProtectedCheckRemoteAddrAndGetHost(&binaryData, t.Conn) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // шлем данные указанному хосту conn2, err := utils.TcpConn(host) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } defer conn2.Close() // шлем тип данных _, err = conn2.Write(utils.DecToBin(2, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } err = utils.WriteSizeAndDataTCPConn(binaryData, conn2) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } }
func (t *TcpServer) Type4() { // данные присылает демон confirmations buf := make([]byte, 4) _, err := t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } blockId := utils.BinToDec(buf) // используется для учета кол-ва подвержденных блоков, т.е. тех, которые есть у большинства нодов hash, err := t.Single("SELECT hash FROM block_chain WHERE id = ?", blockId).String() if err != nil { log.Error("%v", utils.ErrInfo(err)) t.Conn.Write(utils.DecToBin(0, 1)) return } _, err = t.Conn.Write([]byte(hash)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } }
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) }
func (t *TcpServer) Type8() { /* делаем запрос на указанную ноду, чтобы получить оттуда тело блока * запрос шлет демон blocksCollection и queueParserBlocks через p.GetBlocks() */ // размер данных buf := make([]byte, 4) _, err := t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } size := utils.BinToDec(buf) if size < 10485760 { // сами данные binaryData := make([]byte, size) //binaryData, err = ioutil.ReadAll(t.Conn) _, err = io.ReadFull(t.Conn, binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } blockId := utils.BinToDecBytesShift(&binaryData, 4) host, err := utils.ProtectedCheckRemoteAddrAndGetHost(&binaryData, t.Conn) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // шлем данные указанному хосту conn2, err := utils.TcpConn(host) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } defer conn2.Close() // шлем тип данных _, err = conn2.Write(utils.DecToBin(7, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // шлем ID блока _, err = conn2.Write(utils.DecToBin(blockId, 4)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // в ответ получаем размер данных, которые нам хочет передать сервер buf := make([]byte, 4) _, err = conn2.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } dataSize := utils.BinToDec(buf) // и если данных менее 10мб, то получаем их if dataSize < 10485760 { blockBinary := make([]byte, dataSize) /*_, err := conn2.Read(blockBinary) if err != nil { log.Error("%v", utils.ErrInfo(err)) return }*/ //blockBinary, err = ioutil.ReadAll(conn2) _, err = io.ReadFull(conn2, binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // шлем тому, кто запросил блок из демона _, err = t.Conn.Write(blockBinary) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } return } }
func (t *TcpServer) Type11() { /* Получаем данные от send_to_pool */ log.Debug("Type11") // размер данных buf := make([]byte, 4) _, err := t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } size := utils.BinToDec(buf) log.Debug("size: %d", size) if size < 32<<20 { // сами данные log.Debug("read data") binaryData := make([]byte, size) //binaryData, err = ioutil.ReadAll(t.Conn) _, err = io.ReadFull(t.Conn, binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } //log.Debug("binaryData %x", binaryData) userId := utils.BinToDec(utils.BytesShift(&binaryData, 5)) log.Debug("userId %d", userId) // проверим, есть ли такой юзер на пуле inPool, err := t.Single(`SELECT user_id FROM community WHERE user_id=?`, userId).Int64() if inPool <= 0 { log.Error("%v", utils.ErrInfo("inPool<=0")) _, err = t.Conn.Write(utils.DecToBin(0, 1)) return } log.Debug("inPool %d", inPool) filesSign := utils.BytesShift(&binaryData, utils.DecodeLength(&binaryData)) log.Debug("filesSign %x", filesSign) forSign := "" var files []string for i := 0; i < 3; i++ { size := utils.DecodeLength(&binaryData) log.Debug("size %d", size) data := utils.BytesShift(&binaryData, size) //log.Debug("data %x", data) fileType := utils.BinToDec(utils.BytesShift(&data, 1)) log.Debug("fileType %d", fileType) var name string switch fileType { case 0: name = utils.Int64ToStr(userId) + "_user_face.jpg" case 1: name = utils.Int64ToStr(userId) + "_user_profile.jpg" case 2: name = utils.Int64ToStr(userId) + "_user_video.mp4" /*case 3: name = utils.Int64ToStr(userId)+"_user_video.webm" case 4: name = utils.Int64ToStr(userId)+"_user_video.ogv"*/ } forSign = forSign + string(utils.DSha256((data))) + "," log.Debug("forSign %s", forSign) err = ioutil.WriteFile(os.TempDir()+"/"+name, data, 0644) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } files = append(files, name) log.Debug("files %d", files) if len(binaryData) == 0 { break } } if len(forSign) == 0 { log.Error("%v", utils.ErrInfo("len(forSign) == 0")) _, err = t.Conn.Write(utils.DecToBin(0, 1)) return } if len(files) == 3 { forSign = forSign[:len(forSign)-1] } // проверим подпись publicKey, err := t.GetUserPublicKey(userId) resultCheckSign, err := utils.CheckSign([][]byte{[]byte(publicKey)}, forSign, utils.HexToBin(filesSign), true) if err != nil { log.Error("%v", utils.ErrInfo(err)) _, err = t.Conn.Write(utils.DecToBin(0, 1)) return } if resultCheckSign { for i := 0; i < len(files); i++ { utils.CopyFileContents(os.TempDir()+"/"+files[i], *utils.Dir+"/public/"+files[i]) } } else { for i := 0; i < len(files); i++ { os.Remove(os.TempDir() + "/" + files[i]) } } // и возвращаем статус _, err = t.Conn.Write(utils.DecToBin(1, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } else { log.Error("%v", utils.ErrInfo("size>32mb")) } }
func (d *daemon) DisseminatorType1(host string, userId int64, node_public_key string, toBeSent []byte, dataType int64) { log.Debug("host %v / userId %v", host, userId) // шлем данные указанному хосту conn, err := utils.TcpConn(host) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } defer conn.Close() randTestblockHash, err := d.Single("SELECT head_hash FROM queue_testblock").String() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // получаем IV + ключ + зашифрованный текст dataToBeSent, key, iv, err := utils.EncryptData(toBeSent, []byte(node_public_key), randTestblockHash) log.Debug("key: %s", key) log.Debug("iv: %s", iv) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // вначале шлем тип данных, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные n, err := conn.Write(utils.DecToBin(dataType, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("n: %x", n) // т.к. на приеме может быть пул, то нужно дописать в начало user_id, чьим нодовским ключем шифруем dataToBeSent = append(utils.DecToBin(userId, 5), dataToBeSent...) log.Debug("dataToBeSent: %x", dataToBeSent) // в 4-х байтах пишем размер данных, которые пошлем далее size := utils.DecToBin(len(dataToBeSent), 4) n, err = conn.Write(size) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("n: %x", n) n, err = conn.Write(dataToBeSent) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("n: %d / size: %v / len: %d", n, utils.BinToDec(size), len(dataToBeSent)) // в ответ получаем размер данных, которые нам хочет передать сервер buf := make([]byte, 4) n, err = conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("n: %x", n) dataSize := utils.BinToDec(buf) log.Debug("dataSize %d", dataSize) // и если данных менее 1мб, то получаем их if dataSize < 1048576 { encBinaryTxHashes := make([]byte, dataSize) _, err = io.ReadFull(conn, encBinaryTxHashes) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // разбираем полученные данные binaryTxHashes, err := utils.DecryptCFB(iv, encBinaryTxHashes, key) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("binaryTxHashes %x", binaryTxHashes) var binaryTx []byte for { // Разбираем список транзакций txHash := make([]byte, 16) if len(binaryTxHashes) >= 16 { txHash = utils.BytesShift(&binaryTxHashes, 16) } txHash = utils.BinToHex(txHash) log.Debug("txHash %s", txHash) utils.WriteSelectiveLog("SELECT data FROM transactions WHERE hex(hash) = " + string(txHash)) tx, err := d.Single("SELECT data FROM transactions WHERE hex(hash) = ?", txHash).Bytes() log.Debug("tx %x", tx) if err != nil { utils.WriteSelectiveLog(err) log.Error("%v", utils.ErrInfo(err)) return } utils.WriteSelectiveLog("tx: " + string(utils.BinToHex(tx))) if len(tx) > 0 { binaryTx = append(binaryTx, utils.EncodeLengthPlusData(tx)...) } if len(binaryTxHashes) == 0 { break } } log.Debug("binaryTx %x", binaryTx) // шифруем тр-ии. Вначале encData добавляется IV encData, _, err := utils.EncryptCFB(binaryTx, key, iv) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("encData %x", encData) // шлем серверу // в первых 4-х байтах пишем размер данных, которые пошлем далее size := utils.DecToBin(len(encData), 4) _, err = conn.Write(size) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // далее шлем сами данные _, err = conn.Write(encData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } }
/* * просто шлем всем, кто есть в 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) }
/** * Демон, который мониторит таблу 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 (t *TcpServer) Type12() { /* Получаем данные от send_promised_amount_to_pool */ log.Debug("Type12") // размер данных buf := make([]byte, 4) _, err := t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } size := utils.BinToDec(buf) log.Debug("size: %d", size) if size < 32<<20 { // сами данные log.Debug("read data") binaryData := make([]byte, size) _, err = io.ReadFull(t.Conn, binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } //log.Debug("binaryData %x", binaryData) userId := utils.BinToDec(utils.BytesShift(&binaryData, 5)) currencyId := utils.BinToDec(utils.BytesShift(&binaryData, 1)) log.Debug("userId %d", userId) log.Debug("currencyId %d", currencyId) // проверим, есть ли такой юзер на пуле inPool, err := t.Single(`SELECT user_id FROM community WHERE user_id=?`, userId).Int64() if inPool <= 0 { log.Error("%v", utils.ErrInfo("inPool<=0")) _, err = t.Conn.Write(utils.DecToBin(0, 1)) return } log.Debug("inPool %d", inPool) filesSign := utils.BytesShift(&binaryData, utils.DecodeLength(&binaryData)) log.Debug("filesSign %x", filesSign) size := utils.DecodeLength(&binaryData) log.Debug("size %d", size) data := utils.BytesShift(&binaryData, size) //log.Debug("data %x", data) fileType := utils.BinToDec(utils.BytesShift(&data, 1)) log.Debug("fileType %d", fileType) fileName := utils.Int64ToStr(userId) + "_promised_amount_" + utils.Int64ToStr(currencyId) + ".mp4" forSign := string(utils.DSha256((data))) log.Debug("forSign %s", forSign) err = ioutil.WriteFile(os.TempDir()+"/"+fileName, data, 0644) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } if len(forSign) == 0 { log.Error("%v", utils.ErrInfo("len(forSign) == 0")) _, err = t.Conn.Write(utils.DecToBin(0, 1)) return } // проверим подпись publicKey, err := t.GetUserPublicKey(userId) resultCheckSign, err := utils.CheckSign([][]byte{[]byte(publicKey)}, forSign, utils.HexToBin(filesSign), true) if err != nil { log.Error("%v", utils.ErrInfo(err)) _, err = t.Conn.Write(utils.DecToBin(0, 1)) return } if resultCheckSign { utils.CopyFileContents(os.TempDir()+"/"+fileName, *utils.Dir+"/public/"+fileName) } else { os.Remove(os.TempDir() + "/" + fileName) } // и возвращаем статус _, err = t.Conn.Write(utils.DecToBin(1, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } else { log.Error("%v", utils.ErrInfo("size>32mb")) } }
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 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) }
func (d *daemon) chatConnector() { log.Debug("start chatConnector") maxMinerId, err := d.Single("SELECT max(miner_id) FROM miners_data").Int64() if err != nil { log.Error("%v", err) } if maxMinerId == 0 { maxMinerId = 1 } q := "" if d.ConfigIni["db_type"] == "postgresql" { q = "SELECT DISTINCT ON (tcp_host) tcp_host, user_id FROM miners_data WHERE miner_id IN (" + strings.Join(utils.RandSlice(1, maxMinerId, consts.COUNT_CHAT_NODES), ",") + ")" } else { q = "SELECT tcp_host, user_id FROM miners_data WHERE miner_id IN (" + strings.Join(utils.RandSlice(1, maxMinerId, consts.COUNT_CHAT_NODES), ",") + ") GROUP BY tcp_host" } hosts, err := d.GetAll(q, consts.COUNT_CHAT_NODES) if err != nil { log.Error("%v", err) } // исключим себя myTcpHost, err := d.Single(`SELECT tcp_host FROM miners_data WHERE user_id = ?`, myUserIdForChat).String() if err != nil { log.Error("%v", err) } fmt.Println("myTcpHost:", myTcpHost) // исключим хосты, к которым уже подключены var uids string for userId, _ := range utils.ChatOutConnections { uids += utils.Int64ToStr(userId) + "," } if len(uids) > 0 { uids = uids[:len(uids)-1] } existsTcpHost, err := d.GetList(`SELECT tcp_host FROM miners_data WHERE user_id IN (` + uids + `)`).String() if err != nil { log.Error("%v", err) } log.Debug("hosts: %v", hosts) for _, data := range hosts { host := data["tcp_host"] userId := utils.StrToInt64(data["user_id"]) if host == myTcpHost || utils.InSliceString(host, existsTcpHost) { continue } go func(host string, userId int64) { log.Debug("host: %v", host) log.Debug("userId: %d", userId) re := regexp.MustCompile(`(.*?):[0-9]+$`) match := re.FindStringSubmatch(host) log.Debug("match: %v", match) if len(match) != 0 { log.Debug("myUserIdForChat %v", myUserIdForChat) log.Debug("chat host: %v", match[1]+":"+consts.CHAT_PORT) chatHost := match[1] + ":" + consts.CHAT_PORT //chatHost := "192.168.150.30:8087" // проверим, нет ли уже созданных каналов для такого хоста if _, ok := utils.ChatOutConnections[userId]; !ok { // канал для приема тр-ий чата conn, err := net.DialTimeout("tcp", chatHost, 5*time.Second) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } else { log.Debug(conn.RemoteAddr().String(), conn) myUid := utils.DecToBin(myUserIdForChat, 4) log.Debug("myUid %x", myUid) n, err := conn.Write(myUid) log.Debug("n: %d", n) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } n, err = conn.Write(utils.DecToBin(1, 1)) log.Debug("n: %d", n) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } fmt.Println("connector ChatInput", conn.RemoteAddr(), utils.Time()) log.Debug("connector ChatInput %s %v", conn.RemoteAddr(), utils.Time()) utils.ChatMutex.Lock() utils.ChatInConnections[userId] = 1 utils.ChatMutex.Unlock() go utils.ChatInput(conn, userId) } // канал для отправки тр-ий чата conn2, err := net.DialTimeout("tcp", chatHost, 5*time.Second) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } else { log.Debug(conn2.RemoteAddr().String(), conn2) n, err := conn2.Write(utils.DecToBin(myUserIdForChat, 4)) log.Debug("n: %d", n) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } n, err = conn2.Write(utils.DecToBin(0, 1)) log.Debug("n: %d", n) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } fmt.Println("connector ADD", userId, conn2.RemoteAddr(), utils.Time()) log.Debug("connector ADD %v %s %v", userId, conn2.RemoteAddr(), utils.Time()) connChan := make(chan *utils.ChatData, 100) utils.ChatMutex.Lock() utils.ChatOutConnections[userId] = &utils.ChatOutConnectionsType{MessIds: []int64{}, ConnectionChan: connChan} utils.ChatMutex.Unlock() fmt.Println("ChatOutConnections", utils.ChatOutConnections) utils.ChatTxDisseminator(conn2, userId, connChan) } } } }(host, userId) } }
/* * Каждые 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 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 (c *Controller) SendPromisedAmountToPool() (string, error) { if c.SessRestricted != 0 { return "", utils.ErrInfo(errors.New("Permission denied")) } filesSign := c.r.FormValue("filesSign") currencyId := utils.StrToInt64(c.r.FormValue("currencyId")) tcpHost, err := c.Single(`SELECT tcp_host FROM miners_data WHERE user_id = ?`, c.SessUserId).String() if err != nil { return "", utils.ErrInfo(err) } conn, err := net.DialTimeout("tcp", tcpHost, 5*time.Second) if err != nil { return "", utils.ErrInfo(err) } defer conn.Close() conn.SetReadDeadline(time.Now().Add(240 * time.Second)) conn.SetWriteDeadline(time.Now().Add(240 * time.Second)) var data []byte data = append(data, utils.DecToBin(c.SessUserId, 5)...) data = append(data, utils.DecToBin(currencyId, 1)...) data = append(data, utils.EncodeLengthPlusData(filesSign)...) if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_promised_amount_" + utils.Int64ToStr(currencyId) + ".mp4"); err == nil { file, err := ioutil.ReadFile(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_promised_amount_" + utils.Int64ToStr(currencyId) + ".mp4") if err != nil { return "", utils.ErrInfo(err) } data = append(data, utils.EncodeLengthPlusData(append(utils.DecToBin(2, 1), file...))...) } // тип данных _, err = conn.Write(utils.DecToBin(12, 1)) if err != nil { return "", utils.ErrInfo(err) } // в 4-х байтах пишем размер данных, которые пошлем далее size := utils.DecToBin(len(data), 4) _, err = conn.Write(size) if err != nil { return "", utils.ErrInfo(err) } // далее шлем сами данные _, err = conn.Write([]byte(data)) if err != nil { return "", utils.ErrInfo(err) } // в ответ получаем статус buf := make([]byte, 1) _, err = conn.Read(buf) if err != nil { return "", utils.ErrInfo(err) } status := utils.BinToDec(buf) result := "" if status == 1 { result = utils.JsonAnswer("1", "success").String() } else { result = utils.JsonAnswer("error", "error").String() } return result, nil }
func CleaningDb(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "CleaningDb" 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 } curBlockId, err := d.GetBlockId() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // пишем свежие блоки в резервный блокчейн endBlockId, err := utils.GetEndBlockId() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } // чтобы не стопориться тут, а дойти до пересборки БД endBlockId = 4294967295 } log.Debug("curBlockId: %v / endBlockId: %v", curBlockId, endBlockId) if curBlockId-30 > endBlockId { file, err := os.OpenFile(*utils.Dir+"/public/blockchain", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } rows, err := d.Query(d.FormatQuery(` SELECT id, data FROM block_chain WHERE id > ? AND id <= ? ORDER BY id `), endBlockId, curBlockId-30) if err != nil { file.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var id, data string err = rows.Scan(&id, &data) if err != nil { rows.Close() file.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } blockData := append(utils.DecToBin(id, 5), utils.EncodeLengthPlusData(data)...) sizeAndData := append(utils.DecToBin(len(blockData), 5), blockData...) //err := ioutil.WriteFile(*utils.Dir+"/public/blockchain", append(sizeAndData, utils.DecToBin(len(sizeAndData), 5)...), 0644) if _, err = file.Write(append(sizeAndData, utils.DecToBin(len(sizeAndData), 5)...)); err != nil { rows.Close() file.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if err != nil { rows.Close() file.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } rows.Close() file.Close() } autoReload, err := d.Single("SELECT auto_reload FROM config").Int64() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("autoReload: %v", autoReload) if autoReload < 60 { if d.dPrintSleep(utils.ErrInfo("autoReload < 60"), d.sleepTime) { break BEGIN } continue BEGIN } // если main_lock висит более x минут, значит был какой-то сбой mainLock, err := d.Single("SELECT lock_time FROM main_lock WHERE script_name NOT IN ('my_lock', 'cleaning_db')").Int64() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } var infoBlockRestart bool // если с main_lock всё норм, то возможно, что новые блоки не собираются из-за бана нодов if mainLock == 0 || utils.Time()-autoReload < mainLock { timeInfoBlock, err := d.Single(`SELECT time FROM info_block`).Int64() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if utils.Time()-timeInfoBlock > autoReload { // подождем 5 минут и проверим еще раз if d.dSleep(300) { break BEGIN } newTimeInfoBlock, err := d.Single(`SELECT time FROM info_block`).Int64() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // Если за 5 минут info_block тот же, значит обновление блокчейна не идет if newTimeInfoBlock == timeInfoBlock { infoBlockRestart = true } } } log.Debug("mainLock: %v", mainLock) log.Debug("utils.Time(): %v", utils.Time()) if (mainLock > 0 && utils.Time()-autoReload > mainLock) || infoBlockRestart { // ClearDb - убивает демонов, чистит БД, а потом заново запускает демонов // не забываем, что это тоже демон и он должен отчитаться о завершении err = ClearDb(d.chAnswer, GoroutineName) if err != nil { fmt.Println(utils.ErrInfo(err)) if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func (t *TcpServer) Type6() { /** - проверяем, находится ли отправитель на одном с нами уровне - получаем block_id, user_id, mrkl_root, signature - если хэш блока меньше того, что есть у нас в табле testblock, то смотртим, есть ли такой же хэш тр-ий, - если отличается, то загружаем блок от отправителя - если не отличается, то просто обновляем хэш блока у себя данные присылает демон testblockDisseminator */ currentBlockId, err := t.GetBlockId() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } if currentBlockId == 0 { log.Debug("%v", utils.ErrInfo("currentBlockId == 0")) return } buf := make([]byte, 4) _, err = t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } size := utils.BinToDec(buf) log.Debug("size: %v", size) if size < 10485760 { binaryData := make([]byte, size) //binaryData, err = ioutil.ReadAll(t.Conn) _, err = io.ReadFull(t.Conn, binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("binaryData: %x", binaryData) newTestblockBlockId := utils.BinToDecBytesShift(&binaryData, 4) newTestblockTime := utils.BinToDecBytesShift(&binaryData, 4) newTestblockUserId := utils.BinToDecBytesShift(&binaryData, 4) newTestblockMrklRoot := utils.BinToHex(utils.BytesShift(&binaryData, 32)) newTestblockSignatureHex := utils.BinToHex(utils.BytesShift(&binaryData, utils.DecodeLength(&binaryData))) log.Debug("newTestblockBlockId: %v", newTestblockBlockId) log.Debug("newTestblockTime: %v", newTestblockTime) log.Debug("newTestblockUserId: %v", newTestblockUserId) log.Debug("newTestblockMrklRoot: %s", newTestblockMrklRoot) log.Debug("newTestblockSignatureHex: %s", newTestblockSignatureHex) if !utils.CheckInputData(newTestblockBlockId, "int") { log.Debug("%v", utils.ErrInfo("incorrect newTestblockBlockId")) return } if !utils.CheckInputData(newTestblockTime, "int") { log.Debug("%v", utils.ErrInfo("incorrect newTestblockTime")) return } if !utils.CheckInputData(newTestblockUserId, "int") { log.Debug("%v", utils.ErrInfo("incorrect newTestblockUserId")) return } if !utils.CheckInputData(newTestblockMrklRoot, "sha256") { log.Debug("%v", utils.ErrInfo("incorrect newTestblockMrklRoot")) return } /* * Проблема одновременных попыток локнуть. Надо попробовать без локов * */ //t.DbLockGate("6") exists, err := t.Single(` SELECT block_id FROM testblock WHERE status = 'active' `).Int64() if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } if exists == 0 { t.PrintSleep(utils.ErrInfo("null testblock"), 0) return } //prevBlock, myUserId, myMinerId, currentUserId, level, levelsRange, err := t.TestBlock() prevBlock, _, _, _, level, levelsRange, err := t.TestBlock() if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } nodesIds := utils.GetOurLevelNodes(level, levelsRange) log.Debug("nodesIds: %v ", nodesIds) log.Debug("prevBlock: %v ", prevBlock) log.Debug("level: %v ", level) log.Debug("levelsRange: %v ", levelsRange) log.Debug("newTestblockBlockId: %v ", newTestblockBlockId) // проверим, верный ли ID блока if newTestblockBlockId != prevBlock.BlockId+1 { t.PrintSleep(utils.ErrInfo(fmt.Sprintf("newTestblockBlockId != prevBlock.BlockId+1 %d!=%d+1", newTestblockBlockId, prevBlock.BlockId)), 1) return } // проверим, есть ли такой майнер minerId, err := t.Single("SELECT miner_id FROM miners_data WHERE user_id = ?", newTestblockUserId).Int64() if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } if minerId == 0 { t.PrintSleep(utils.ErrInfo("minerId == 0"), 0) return } log.Debug("minerId: %v ", minerId) // проверим, точно ли отправитель с нашего уровня if !utils.InSliceInt64(minerId, nodesIds) { t.PrintSleep(utils.ErrInfo("!InSliceInt64(minerId, nodesIds)"), 0) return } // допустимая погрешность во времени генерации блока maxErrorTime := t.variables.Int64["error_time"] // получим значения для сна sleep, err := t.GetGenSleep(prevBlock, level) if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } // исключим тех, кто сгенерил блок слишком рано if prevBlock.Time+sleep-newTestblockTime > maxErrorTime { t.PrintSleep(utils.ErrInfo("prevBlock.Time + sleep - newTestblockTime > maxErrorTime"), 0) return } // исключим тех, кто сгенерил блок с бегущими часами if newTestblockTime > utils.Time() { t.PrintSleep(utils.ErrInfo("newTestblockTime > Time()"), 0) return } // получим хэш заголовка newHeaderHash := utils.DSha256(fmt.Sprintf("%v,%v,%v", newTestblockUserId, newTestblockBlockId, prevBlock.HeadHash)) myTestblock, err := t.OneRow(` SELECT block_id, user_id, hex(mrkl_root) as mrkl_root, hex(signature) as signature FROM testblock WHERE status = 'active' `).String() if len(myTestblock) > 0 { if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } // получим хэш заголовка myHeaderHash := utils.DSha256(fmt.Sprintf("%v,%v,%v", myTestblock["user_id"], myTestblock["block_id"], prevBlock.HeadHash)) // у кого меньше хэш, тот и круче hash1 := big.NewInt(0) hash1.SetString(string(newHeaderHash), 16) hash2 := big.NewInt(0) hash2.SetString(string(myHeaderHash), 16) log.Debug("%v", hash1.Cmp(hash2)) //if HexToDecBig(newHeaderHash) > string(myHeaderHash) { if hash1.Cmp(hash2) == 1 { t.PrintSleep(utils.ErrInfo(fmt.Sprintf("newHeaderHash > myHeaderHash (%s > %s)", newHeaderHash, myHeaderHash)), 0) return } /* т.к. на данном этапе в большинстве случаев наш текущий блок будет заменен, * то нужно парсить его, рассылать другим нодам и дождаться окончания проверки */ err = t.ExecSql("UPDATE testblock SET status = 'pending'") if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } } // если отличается, то загружаем недостающии тр-ии от отправителя if string(newTestblockMrklRoot) != myTestblock["mrkl_root"] { log.Debug("download new tx") sendData := "" // получим все имеющиеся у нас тр-ии, которые еще не попали в блоки txArray, err := t.GetMap(`SELECT hex(hash) as hash, data FROM transactions`, "hash", "data") if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } for hash, _ := range txArray { sendData += hash } err = utils.WriteSizeAndData([]byte(sendData), t.Conn) if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } /* в ответ получаем: BLOCK_ID 4 TIME 4 USER_ID 5 SIGN от 128 до 512 байт. Подпись от TYPE, BLOCK_ID, PREV_BLOCK_HASH, TIME, USER_ID, LEVEL, MRKL_ROOT Размер всех тр-ий, размер 1 тр-ии, тело тр-ии. Хэши три-ий (порядок тр-ий) */ buf := make([]byte, 4) _, err = t.Conn.Read(buf) if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } dataSize := utils.BinToDec(buf) log.Debug("dataSize %d", dataSize) // и если данных менее 10мб, то получаем их if dataSize < 10485760 { binaryData := make([]byte, dataSize) //binaryData, err = ioutil.ReadAll(t.Conn) _, err = io.ReadFull(t.Conn, binaryData) if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } // Разбираем полученные бинарные данные newTestblockBlockId := utils.BinToDecBytesShift(&binaryData, 4) newTestblockTime := utils.BinToDecBytesShift(&binaryData, 4) newTestblockUserId := utils.BinToDecBytesShift(&binaryData, 5) newTestblockSignature := utils.BytesShift(&binaryData, utils.DecodeLength(&binaryData)) log.Debug("newTestblockBlockId %v", newTestblockBlockId) log.Debug("newTestblockTime %v", newTestblockTime) log.Debug("newTestblockUserId %v", newTestblockUserId) log.Debug("newTestblockSignature %x", newTestblockSignature) // недостающие тр-ии length := utils.DecodeLength(&binaryData) // размер всех тр-ий txBinary := utils.BytesShift(&binaryData, length) for { // берем по одной тр-ии length := utils.DecodeLength(&txBinary) // размер всех тр-ий if length == 0 { break } log.Debug("length %d", length) tx := utils.BytesShift(&txBinary, length) log.Debug("tx %x", tx) txArray[string(utils.Md5(tx))] = string(tx) } // порядок тр-ий var orderHashArray []string for { orderHashArray = append(orderHashArray, string(utils.BinToHex(utils.BytesShift(&binaryData, 16)))) if len(binaryData) == 0 { break } } // сортируем и наши и полученные транзакции var transactions []byte for _, txMd5 := range orderHashArray { transactions = append(transactions, utils.EncodeLengthPlusData([]byte(txArray[txMd5]))...) } // формируем блок, который далее будем тщательно проверять /* Заголовок (от 143 до 527 байт ) TYPE (0-блок, 1-тр-я) 1 BLOCK_ID 4 TIME 4 USER_ID 5 LEVEL 1 SIGN от 128 до 512 байт. Подпись от TYPE, BLOCK_ID, PREV_BLOCK_HASH, TIME, USER_ID, LEVEL, MRKL_ROOT Далее - тело блока (Тр-ии) */ newBlockIdBinary := utils.DecToBin(newTestblockBlockId, 4) timeBinary := utils.DecToBin(newTestblockTime, 4) userIdBinary := utils.DecToBin(newTestblockUserId, 5) levelBinary := utils.DecToBin(level, 1) newBlockHeader := utils.DecToBin(0, 1) // 0 - это блок newBlockHeader = append(newBlockHeader, newBlockIdBinary...) newBlockHeader = append(newBlockHeader, timeBinary...) newBlockHeader = append(newBlockHeader, userIdBinary...) newBlockHeader = append(newBlockHeader, levelBinary...) // $level пишем, чтобы при расчете времени ожидания в следующем блоке не пришлось узнавать, какой был max_miner_id newBlockHeader = append(newBlockHeader, utils.EncodeLengthPlusData(newTestblockSignature)...) newBlockHex := utils.BinToHex(append(newBlockHeader, transactions...)) // и передаем блок для обратотки через демон queue_parser_testblock // т.к. есть запросы к log_time_, а их можно выполнять только по очереди err = t.ExecSql(`DELETE FROM queue_testblock WHERE hex(head_hash) = ?`, newHeaderHash) if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } log.Debug("INSERT INTO queue_testblock (head_hash, data) VALUES (%s, %s)", newHeaderHash, newBlockHex) err = t.ExecSql(`INSERT INTO queue_testblock (head_hash, data) VALUES ([hex], [hex])`, newHeaderHash, newBlockHex) if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } } } else { // если всё нормально, то пишем в таблу testblock новые данные exists, err := t.Single(`SELECT block_id FROM testblock`).Int64() if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } if exists == 0 { err = t.ExecSql(`INSERT INTO testblock (block_id, time, level, user_id, header_hash, signature, mrkl_root) VALUES (?, ?, ?, ?, [hex], [hex], [hex])`, newTestblockBlockId, newTestblockTime, level, newTestblockUserId, string(newHeaderHash), newTestblockSignatureHex, string(newTestblockMrklRoot)) if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } } else { err = t.ExecSql(` UPDATE testblock SET time = ?, user_id = ?, header_hash = [hex], signature = [hex] `, newTestblockTime, newTestblockUserId, string(newHeaderHash), string(newTestblockSignatureHex)) if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } } } err = t.ExecSql("UPDATE testblock SET status = 'active'") if err != nil { t.PrintSleep(utils.ErrInfo(err), 0) return } //t.DbUnlockGate("6") } }
func (t *TcpServer) Type1() { log.Debug("dataType: 1") // размер данных buf := make([]byte, 4) n, err := t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } size := utils.BinToDec(buf) log.Debug("size: %v / n: %v", size, n) if size < 10485760 { // сами данные binaryData := make([]byte, size) log.Debug("ReadAll 0") _, err = io.ReadFull(t.Conn, binaryData) log.Debug("ReadAll 1") if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("binaryData: %x", binaryData) /* * принимаем зашифрованный список тр-ий от демона disseminator, которые есть у отправителя * Блоки не качаем тут, т.к. может быть цепочка блоков, а их качать долго * тр-ии качаем тут, т.к. они мелкие и точно скачаются за 60 сек * */ key, iv, decryptedBinData, err := t.DecryptData(&binaryData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("key: %v / iv: %v", key, iv) /* * структура данных: * user_id - 5 байт * type - 1 байт. 0 - блок, 1 - список тр-ий * {если type==1}: * <любое кол-во следующих наборов> * high_rate - 1 байт * tx_hash - 16 байт * </> * {если type==0}: * block_id - 3 байта * hash - 32 байт * head_hash - 32 байт * <любое кол-во следующих наборов> * high_rate - 1 байт * tx_hash - 16 байт * </> * */ blockId, err := t.GetBlockId() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("decryptedBinData: %x", decryptedBinData) // user_id отправителя, чтобы знать у кого брать данные, когда они будут скачиваться другим скриптом newDataUserId := utils.BinToDec(utils.BytesShift(&decryptedBinData, 5)) log.Debug("newDataUserId: %d", newDataUserId) // данные могут быть отправлены юзером, который уже не майнер minerId, err := t.Single("SELECT miner_id FROM miners_data WHERE user_id = ? AND miner_id > 0", newDataUserId).Int64() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("minerId: %v", minerId) if minerId == 0 { log.Error("%v", utils.ErrInfo(err)) return } // если 0 - значит вначале идет инфа о блоке, если 1 - значит сразу идет набор хэшей тр-ий newDataType := utils.BinToDecBytesShift(&decryptedBinData, 1) log.Debug("newDataType: %d", newDataType) if newDataType == 0 { // ID блока, чтобы не скачать старый блок newDataBlockId := utils.BinToDecBytesShift(&decryptedBinData, 3) log.Debug("newDataBlockId: %d / blockId: %d", newDataBlockId, blockId) // нет смысла принимать старые блоки if newDataBlockId >= blockId { // Это хэш для соревнования, у кого меньше хэш newDataHash := utils.BinToHex(utils.BytesShift(&decryptedBinData, 32)) // Для доп. соревнования, если head_hash равны (шалит кто-то из майнеров и позже будет за такое забанен) newDataHeadHash := utils.BinToHex(utils.BytesShift(&decryptedBinData, 32)) err = t.ExecSql(`DELETE FROM queue_blocks WHERE hex(hash) = ?`, newDataHash) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } err = t.ExecSql(` INSERT INTO queue_blocks ( hash, head_hash, user_id, block_id ) VALUES ( [hex], [hex], ?, ? )`, newDataHash, newDataHeadHash, newDataUserId, newDataBlockId) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } } log.Debug("decryptedBinData: %x", decryptedBinData) var needTx []byte // Разбираем список транзакций if len(decryptedBinData) == 0 { log.Debug("%v", utils.ErrInfo("len(decryptedBinData) == 0")) return } for { // 1 - это админские тр-ии, 0 - обычные newDataHighRate := utils.BinToDecBytesShift(&decryptedBinData, 1) if len(decryptedBinData) < 16 { log.Debug("%v", utils.ErrInfo("len(decryptedBinData) < 16")) return } log.Debug("newDataHighRate: %v", newDataHighRate) newDataTxHash := utils.BinToHex(utils.BytesShift(&decryptedBinData, 16)) if len(newDataTxHash) == 0 { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("newDataTxHash %s", newDataTxHash) // проверим, нет ли у нас такой тр-ии exists, err := t.Single("SELECT count(hash) FROM log_transactions WHERE hex(hash) = ?", newDataTxHash).Int64() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } if exists > 0 { log.Debug("exists") continue } needTx = append(needTx, utils.HexToBin(newDataTxHash)...) if len(decryptedBinData) == 0 { break } } if len(needTx) == 0 { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("needTx: %v", needTx) // шифруем данные. ключ $key сеансовый, iv тоже encData, _, err := utils.EncryptCFB(needTx, key, iv) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // в 4-х байтах пишем размер данных, которые пошлем далее size := utils.DecToBin(len(encData), 4) _, err = t.Conn.Write(size) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("size: %v", len(encData)) log.Debug("encData: %x", encData) // далее шлем сами данные _, err = t.Conn.Write(encData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // в ответ получаем размер данных, которые нам хочет передать сервер buf := make([]byte, 4) _, err = t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } dataSize := utils.BinToDec(buf) log.Debug("dataSize %v", dataSize) // и если данных менее 10мб, то получаем их if dataSize < 10485760 { encBinaryTxs := make([]byte, dataSize) _, err = io.ReadFull(t.Conn, encBinaryTxs) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // разбираем полученные данные log.Debug("encBinaryTxs %x", encBinaryTxs) // уберем IV из начала utils.BytesShift(&encBinaryTxs, 16) // декриптуем binaryTxs, err := utils.DecryptCFB(iv, encBinaryTxs, key) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } log.Debug("binaryTxs %x", binaryTxs) for { txSize := utils.DecodeLength(&binaryTxs) if int64(len(binaryTxs)) < txSize { log.Error("%v", utils.ErrInfo(err)) return } txBinData := utils.BytesShift(&binaryTxs, txSize) if len(txBinData) == 0 { log.Error("%v", utils.ErrInfo(err)) return } txHex := utils.BinToHex(txBinData) // проверим размер if int64(len(txBinData)) > t.variables.Int64["max_tx_size"] { log.Debug("%v", utils.ErrInfo("len(txBinData) > max_tx_size")) return } newDataHighRate := 0 // временно для тестов log.Debug("INSERT INTO queue_tx (hash, high_rate, data) %s, %d, %s", utils.Md5(txBinData), newDataHighRate, txHex) err = t.ExecSql(`INSERT INTO queue_tx (hash, high_rate, data) VALUES ([hex], ?, [hex])`, utils.Md5(txBinData), newDataHighRate, txHex) if len(txBinData) == 0 { log.Error("%v", utils.ErrInfo(err)) return } } } } }
func QueueParserTestblock(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "QueueParserTestblock" 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 = 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 } err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } data, err := d.OneRow("SELECT * FROM queue_testblock ORDER BY head_hash ASC").String() if err != nil { if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue } if len(data) == 0 { if d.unlockPrintSleepInfo(utils.ErrInfo(errors.New("len(data) == 0")), d.sleepTime) { break BEGIN } continue } newBlock := []byte(data["data"]) newHeaderHash := utils.BinToHex([]byte(data["head_hash"])) tx := utils.DeleteHeader(newBlock) // сразу можно удалять данные из таблы-очереди err = d.ExecSql("DELETE FROM queue_testblock WHERE hex(head_hash) = ?", newHeaderHash) if err != nil { if d.unlockPrintSleep(utils.ErrInfo(errors.New("len(data) == 0")), d.sleepTime) { break BEGIN } continue } // прежде всего нужно проверить, а нет ли в этом блоке ошибок с несовметимыми тр-ми // при полной проверке, а не только фронтальной проблем с несовместимыми тр-ми не будет, т.к. там даные сразу пишутся в таблицы // а тут у нас данные пишутся только в log_time_ // и сами тр-ии пишем в отдельную таблу p := new(dcparser.Parser) p.DCDB = d.DCDB if len(tx) > 0 { log.Debug("len(tx): %d", len(tx)) for { log.Debug("tx: %x", tx) txSize := utils.DecodeLength(&tx) log.Debug("txSize: %d", txSize) // отделим одну транзакцию от списка транзакций txBinaryData := utils.BytesShift(&tx, txSize) log.Debug("txBinaryData: %x", txBinaryData) // проверим, нет ли несовместимых тр-ий fatalError, waitError, _, _, _, _ := p.ClearIncompatibleTx(txBinaryData, false) if len(fatalError) > 0 || len(waitError) > 0 { if d.unlockPrintSleep(utils.ErrInfo(errors.New(" len(fatalError) > 0 || len(waitError) > 0")), d.sleepTime) { break BEGIN } continue BEGIN } if len(tx) == 0 { break } } } // откатим тр-ии тестблока, но не удаляя их, т.к. далее еще можем их вернуть p.RollbackTransactionsTestblock(false) // проверим блок, который получился с данными, которые прислал другой нод p.BinaryData = newBlock err = p.ParseDataGate(false) if err != nil { log.Error("%v", err) // т.к. мы откатили наши тр-ии из transactions_testblock, то теперь нужно обработать их по новой // получим наши транзакции в 1 бинарнике, просто для удобства var myTestBlockBody []byte transactionsTestblock, err := d.GetAll("SELECT data FROM transactions_testblock ORDER BY id ASC", -1) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } for _, data := range transactionsTestblock { myTestBlockBody = append(myTestBlockBody, []byte(data["data"])...) } if len(myTestBlockBody) > 0 { p.BinaryData = append(utils.DecToBin(0, 1), myTestBlockBody...) err = p.ParseDataGate(true) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } } else { // наши тр-ии уже не актуальны, т.к. мы их откатили err = d.ExecSql("DELETE FROM transactions_testblock") if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } exists, err := d.Single(`SELECT block_id FROM testblock`).Int64() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } return } if exists > 0 { // если всё нормально, то пишем в таблу testblock новые тр-ии и новые данные по юзеру их сгенерившему err = d.ExecSql(` UPDATE testblock SET time = ?, user_id = ?, header_hash = [hex], signature = [hex], mrkl_root = [hex] `, p.BlockData.Time, p.BlockData.UserId, newHeaderHash, utils.BinToHex(p.BlockData.Sign), p.MrklRoot) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } // и сами тр-ии пишем в отдельную таблу if len(tx) > 0 { for { txSize := utils.DecodeLength(&tx) // отчекрыжим одну транзакцию от списка транзакций txBinaryData := utils.BytesShift(&tx, txSize) // получим тип тр-ии и юзера txType, userId, toUserId := utils.GetTxTypeAndUserId(txBinaryData) md5 := utils.Md5(txBinaryData) dataHex := utils.BinToHex(txBinaryData) 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("INSERT INTO transactions_testblock (hash, data, type, user_id, third_var) VALUES ([hex], [hex], ?, ?, ?)", md5, dataHex, txType, userId, toUserId) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if len(tx) == 0 { break } } } // удаляем всё, где хэш больше нашего err = d.ExecSql("DELETE FROM queue_testblock WHERE hex(head_hash) > ?", newHeaderHash) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // возможно нужно откатить и тр-ии с verified=1 и used=0 из transactions // т.к. в transactions может быть тр-ия на удаление банкноты // и в transactions_testblock только что была залита такая же тр-ия // выходит, что блок, который будет сгенерен на основе transactions будет ошибочным // или при откате transactions будет сделан вычет из log_time_.... // и выйдет что попавшая в блок тр-я из transactions_testblock попала минуя запись log_time_.... err = p.RollbackTransactions() if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
/* * Каждые 2 недели собираем инфу о голосах за % и создаем тр-ию, которая * попадет в 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 (c *Controller) UploadVideo() (string, error) { if c.SessRestricted != 0 { return "", utils.ErrInfo(errors.New("Permission denied")) } var binaryVideo []byte c.r.ParseMultipartForm(32 << 20) file, _, err := c.r.FormFile("file") if err != nil { return "", utils.ErrInfo(err) } videoBuffer := new(bytes.Buffer) _, err = io.Copy(videoBuffer, file) if err != nil { return "", utils.ErrInfo(err) } defer file.Close() binaryVideo = videoBuffer.Bytes() fmt.Println(c.r.MultipartForm.File["file"][0].Filename) fmt.Println(c.r.MultipartForm.File["file"][0].Header.Get("Content-Type")) fmt.Println(c.r.MultipartForm.Value["type"][0]) var contentType, videoType string if _, ok := c.r.MultipartForm.File["file"]; ok { contentType = c.r.MultipartForm.File["file"][0].Header.Get("Content-Type") } if _, ok := c.r.MultipartForm.Value["type"]; ok { videoType = c.r.MultipartForm.Value["type"][0] } end := "mp4" switch contentType { case "video/mp4", "video/quicktime": end = "mp4" case "video/ogg": end = "ogv" case "video/webm": end = "webm" case "video/3gpp": fmt.Println("3gpp") conn, err := net.DialTimeout("tcp", "3gp.dcoin.club:8099", 5*time.Second) if err != nil { return "", utils.ErrInfo(err) } defer conn.Close() conn.SetReadDeadline(time.Now().Add(240 * time.Second)) conn.SetWriteDeadline(time.Now().Add(240 * time.Second)) // в 4-х байтах пишем размер данных, которые пошлем далее size := utils.DecToBin(len(videoBuffer.Bytes()), 4) _, err = conn.Write(size) if err != nil { return "", utils.ErrInfo(err) } // далее шлем сами данные _, err = conn.Write(videoBuffer.Bytes()) if err != nil { return "", utils.ErrInfo(err) } // в ответ получаем размер данных, которые нам хочет передать сервер buf := make([]byte, 4) n, err := conn.Read(buf) if err != nil { return "", utils.ErrInfo(err) } log.Debug("dataSize buf: %x / get: %v", buf, n) // и если данных менее 10мб, то получаем их dataSize := utils.BinToDec(buf) var binaryBlock []byte log.Debug("dataSize: %v", dataSize) if dataSize < 10485760 && dataSize > 0 { binaryBlock = make([]byte, dataSize) //binaryBlock, err = ioutil.ReadAll(conn) _, err = io.ReadFull(conn, binaryBlock) if err != nil { return "", utils.ErrInfo(err) } log.Debug("len(binaryBlock):", len(binaryBlock)) binaryVideo = binaryBlock } } log.Debug(videoType, end) var name string if videoType == "user_video" { name = "public/" + utils.Int64ToStr(c.SessUserId) + "_user_video." + end } else { x := strings.Split(videoType, "-") if len(x) < 2 { if err != nil { return "", utils.ErrInfo(err) } } name = "public/" + utils.Int64ToStr(c.SessUserId) + "_promised_amount_" + x[1] + "." + end } log.Debug(*utils.Dir + "/" + name) err = ioutil.WriteFile(*utils.Dir+"/"+name, binaryVideo, 0644) if err != nil { return "", utils.ErrInfo(err) } return utils.JsonAnswer(string(utils.DSha256(binaryVideo)), "success").String(), nil }
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) }
func (c *Controller) SendToPool() (string, error) { if c.SessRestricted != 0 { return "", utils.ErrInfo(errors.New("Permission denied")) } filesSign := c.r.FormValue("filesSign") poolUid := utils.StrToInt64(c.r.FormValue("poolUid")) data_, err := c.OneRow(`SELECT tcp_host, http_host FROM miners_data WHERE user_id = ?`, poolUid).String() tcpHost := data_["tcp_host"] httpHost := data_["http_host"] if err != nil { return "", utils.ErrInfo(err) } conn, err := net.DialTimeout("tcp", tcpHost, 5*time.Second) if err != nil { return "", utils.ErrInfo(err) } defer conn.Close() conn.SetReadDeadline(time.Now().Add(240 * time.Second)) conn.SetWriteDeadline(time.Now().Add(240 * time.Second)) var data []byte data = append(data, utils.DecToBin(c.SessUserId, 5)...) data = append(data, utils.EncodeLengthPlusData(filesSign)...) if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg"); err == nil { file, err := ioutil.ReadFile(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg") if err != nil { return "", utils.ErrInfo(err) } data = append(data, utils.EncodeLengthPlusData(append(utils.DecToBin(0, 1), file...))...) } if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg"); err == nil { file, err := ioutil.ReadFile(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg") if err != nil { return "", utils.ErrInfo(err) } data = append(data, utils.EncodeLengthPlusData(append(utils.DecToBin(1, 1), file...))...) } if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.mp4"); err == nil { file, err := ioutil.ReadFile(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.mp4") if err != nil { return "", utils.ErrInfo(err) } data = append(data, utils.EncodeLengthPlusData(append(utils.DecToBin(2, 1), file...))...) } // тип данных _, err = conn.Write(utils.DecToBin(11, 1)) if err != nil { return "", utils.ErrInfo(err) } // в 4-х байтах пишем размер данных, которые пошлем далее size := utils.DecToBin(len(data), 4) _, err = conn.Write(size) if err != nil { return "", utils.ErrInfo(err) } // далее шлем сами данные _, err = conn.Write([]byte(data)) if err != nil { return "", utils.ErrInfo(err) } // в ответ получаем статус buf := make([]byte, 1) _, err = conn.Read(buf) if err != nil { return "", utils.ErrInfo(err) } status := utils.BinToDec(buf) result := "" if status == 1 { result = utils.JsonAnswer("1", "success").String() c.ExecSql(`UPDATE `+c.MyPrefix+`my_table SET tcp_host = ?, http_host = ?`, tcpHost, httpHost) } else { result = utils.JsonAnswer("error", "error").String() } return result, nil }
/** Обработка данных (блоков или транзакций), пришедших с гейта. Только проверка. */ func (p *Parser) ParseDataGate(onlyTx bool) error { var err error p.dataPre() p.TxIds = []string{} p.Variables, err = p.GetAllVariables() if err != nil { return utils.ErrInfo(err) } transactionBinaryData := p.BinaryData var transactionBinaryDataFull []byte // если это транзакции (type>0), а не блок (type==0) if p.dataType > 0 { // проверим, есть ли такой тип тр-ий if len(consts.TxTypes[p.dataType]) == 0 { return p.ErrInfo("Incorrect tx type " + utils.IntToStr(p.dataType)) } log.Debug("p.dataType %v", p.dataType) transactionBinaryData = append(utils.DecToBin(int64(p.dataType), 1), transactionBinaryData...) transactionBinaryDataFull = transactionBinaryData // нет ли хэша этой тр-ии у нас в БД? err = p.CheckLogTx(transactionBinaryDataFull) if err != nil { return p.ErrInfo(err) } p.TxHash = utils.Md5(transactionBinaryData) // преобразуем бинарные данные транзакции в массив p.TxSlice, err = p.ParseTransaction(&transactionBinaryData) if err != nil { return p.ErrInfo(err) } log.Debug("p.TxSlice", p.TxSlice) if len(p.TxSlice) < 3 { return p.ErrInfo(errors.New("len(p.TxSlice) < 3")) } // время транзакции может быть немного больше, чем время на ноде. // у нода может быть просто не настроено время. // время транзакции используется только для борьбы с атаками вчерашними транзакциями. // А т.к. мы храним хэши в log_transaction за 36 часов, то боятся нечего. curTime := utils.Time() if utils.BytesToInt64(p.TxSlice[2])-consts.MAX_TX_FORW > curTime || utils.BytesToInt64(p.TxSlice[2]) < curTime-consts.MAX_TX_BACK { return p.ErrInfo(errors.New("incorrect tx time")) } // $this->transaction_array[3] могут подсунуть пустой if !utils.CheckInputData(p.TxSlice[3], "bigint") { return p.ErrInfo(errors.New("incorrect user id")) } } // если это блок if p.dataType == 0 { txCounter := make(map[int64]int64) // если есть $only_tx=true, то значит идет восстановление уже проверенного блока и заголовок не требуется if !onlyTx { err = p.ParseBlock() if err != nil { return p.ErrInfo(err) } // проверим данные, указанные в заголовке блока err = p.CheckBlockHeader() if err != nil { return p.ErrInfo(err) } } log.Debug("onlyTx", onlyTx) // если в ходе проверки тр-ий возникает ошибка, то вызываем откатчик всех занесенных тр-ий. Эта переменная для него p.fullTxBinaryData = p.BinaryData var txForRollbackTo []byte if len(p.BinaryData) > 0 { for { transactionSize := utils.DecodeLength(&p.BinaryData) if len(p.BinaryData) == 0 { return utils.ErrInfo(fmt.Errorf("empty BinaryData")) } // отчекрыжим одну транзакцию от списка транзакций transactionBinaryData := utils.BytesShift(&p.BinaryData, transactionSize) transactionBinaryDataFull = transactionBinaryData // добавляем взятую тр-ию в набор тр-ий для RollbackTo, в котором пойдем в обратном порядке txForRollbackTo = append(txForRollbackTo, utils.EncodeLengthPlusData(transactionBinaryData)...) // нет ли хэша этой тр-ии у нас в БД? err = p.CheckLogTx(transactionBinaryDataFull) if err != nil { p.RollbackTo(txForRollbackTo, true, false) return p.ErrInfo(err) } p.TxHash = utils.Md5(transactionBinaryData) p.TxSlice, err = p.ParseTransaction(&transactionBinaryData) log.Debug("p.TxSlice %s", p.TxSlice) if err != nil { p.RollbackTo(txForRollbackTo, true, false) return p.ErrInfo(err) } var userId int64 // txSlice[3] могут подсунуть пустой if len(p.TxSlice) > 3 { if !utils.CheckInputData(p.TxSlice[3], "int64") { return utils.ErrInfo(fmt.Errorf("empty user_id")) } else { userId = utils.BytesToInt64(p.TxSlice[3]) } } else { return utils.ErrInfo(fmt.Errorf("empty user_id")) } // считаем по каждому юзеру, сколько в блоке от него транзакций txCounter[userId]++ // чтобы 1 юзер не смог прислать дос-блок размером в 10гб, который заполнит своими же транзакциями if txCounter[userId] > p.Variables.Int64["max_block_user_transactions"] { p.RollbackTo(txForRollbackTo, true, false) return utils.ErrInfo(fmt.Errorf("max_block_user_transactions")) } // проверим, есть ли такой тип тр-ий _, ok := consts.TxTypes[utils.BytesToInt(p.TxSlice[1])] if !ok { return utils.ErrInfo(fmt.Errorf("nonexistent type")) } p.TxMap = map[string][]byte{} // для статы p.TxIds = append(p.TxIds, string(p.TxSlice[1])) MethodName := consts.TxTypes[utils.BytesToInt(p.TxSlice[1])] log.Debug("MethodName", MethodName+"Init") err_ := utils.CallMethod(p, MethodName+"Init") if _, ok := err_.(error); ok { log.Debug("error: %v", err) p.RollbackTo(txForRollbackTo, true, true) return utils.ErrInfo(err_.(error)) } log.Debug("MethodName", MethodName+"Front") err_ = utils.CallMethod(p, MethodName+"Front") if _, ok := err_.(error); ok { log.Debug("error: %v", err) p.RollbackTo(txForRollbackTo, true, true) return utils.ErrInfo(err_.(error)) } // пишем хэш тр-ии в лог err = p.InsertInLogTx(transactionBinaryDataFull, utils.BytesToInt64(p.TxMap["time"])) if err != nil { return utils.ErrInfo(err) } if len(p.BinaryData) == 0 { break } } } } else { // Оперативные транзакции MethodName := consts.TxTypes[p.dataType] log.Debug("MethodName", MethodName+"Init") err_ := utils.CallMethod(p, MethodName+"Init") if _, ok := err_.(error); ok { return utils.ErrInfo(err_.(error)) } log.Debug("MethodName", MethodName+"Front") err_ = utils.CallMethod(p, MethodName+"Front") if _, ok := err_.(error); ok { return utils.ErrInfo(err_.(error)) } // пишем хэш тр-ии в лог err = p.InsertInLogTx(transactionBinaryDataFull, utils.BytesToInt64(p.TxMap["time"])) if err != nil { return utils.ErrInfo(err) } } return nil }
func (t *TcpServer) Type5() { // данные присылает демон connector buf := make([]byte, 5) _, err := t.Conn.Read(buf) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } userId := utils.BinToDec(buf) log.Debug("userId: %d", userId) // если работаем в режиме пула, то нужно проверить, верный ли у юзера нодовский ключ community, err := t.GetCommunityUsers() if err != nil { log.Error("%v", utils.ErrInfo(err)) t.Conn.Write(utils.DecToBin(0, 1)) return } if len(community) > 0 { allTables, err := t.GetAllTables() if err != nil { log.Error("%v", utils.ErrInfo(err)) t.Conn.Write(utils.DecToBin(0, 1)) return } keyTable := utils.Int64ToStr(userId) + "_my_node_keys" if !utils.InSliceString(keyTable, allTables) { log.Error("incorrect user_id %d", userId) t.Conn.Write(utils.DecToBin(0, 1)) return } myBlockId, err := t.GetMyBlockId() if err != nil { log.Error("%v", utils.ErrInfo(err)) t.Conn.Write(utils.DecToBin(0, 1)) return } myNodeKey, err := t.Single(` SELECT public_key FROM `+keyTable+` WHERE block_id = (SELECT max(block_id) FROM `+keyTable+`) AND block_id < ? `, myBlockId).String() if err != nil { log.Error("%v", utils.ErrInfo(err)) t.Conn.Write(utils.DecToBin(0, 1)) return } if len(myNodeKey) == 0 { log.Error("len(myNodeKey) userId %d", userId) t.Conn.Write(utils.DecToBin(0, 1)) return } nodePublicKey, err := t.GetNodePublicKey(userId) if err != nil { log.Error("%v", utils.ErrInfo(err)) t.Conn.Write(utils.DecToBin(0, 1)) return } if myNodeKey != string(nodePublicKey) { log.Error("%v", utils.ErrInfo("myNodeKey != nodePublicKey")) t.Conn.Write(utils.DecToBin(0, 1)) return } // всё норм, шлем 1 _, err = t.Conn.Write(utils.DecToBin(1, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } else { // всё норм, шлем 1 _, err = t.Conn.Write(utils.DecToBin(1, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } } }