Exemplo n.º 1
0
func (p *Parser) ParseDataLite() error {
	p.dataPre()
	if p.dataType != 0 { // парсим только блоки
		return utils.ErrInfo(fmt.Errorf("incorrect dataType"))
	}
	var err error
	p.Variables, err = p.GetAllVariables()
	if err != nil {
		return utils.ErrInfo(err)
	}
	err = p.ParseBlock()
	if err != nil {
		return utils.ErrInfo(err)
	}

	if len(p.BinaryData) > 0 {
		i := 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

			p.TxHash = utils.Md5(transactionBinaryData)
			p.TxSlice, err = p.ParseTransaction(&transactionBinaryData)

			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("%v", err)
				return utils.ErrInfo(err_.(error))
			}
			p.TxMap["md5hash"] = utils.Md5(transactionBinaryDataFull)
			p.TxMapArr = append(p.TxMapArr, p.TxMap)
			//p.TxMapsArr = append(p.TxMapsArr, p.TxMaps)
			if len(p.BinaryData) == 0 {
				break
			}
			i++
		}
	}

	return nil
}
Exemplo n.º 2
0
/**
Обработка данных (блоков или транзакций), пришедших с гейта. Только проверка.
*/
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
}
Exemplo n.º 3
0
/**
 * Занесение данных из блока в БД
 * используется только в testblock_is_ready
 */
func (p *Parser) ParseDataFront() error {

	p.TxIds = []string{}
	p.dataPre()
	if p.dataType == 0 {
		// инфа о предыдущем блоке (т.е. последнем занесенном)
		err := p.GetInfoBlock()
		if err != nil {
			return p.ErrInfo(err)
		}

		utils.WriteSelectiveLog("DELETE FROM transactions WHERE used=1")
		affect, err := p.ExecSqlGetAffect("DELETE FROM transactions WHERE used = 1")
		if err != nil {
			utils.WriteSelectiveLog(err)
			return p.ErrInfo(err)
		}
		utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect))

		// разбор блока
		err = p.ParseBlock()
		if err != nil {
			return utils.ErrInfo(err)
		}

		p.Variables, err = p.GetAllVariables()
		if err != nil {
			return utils.ErrInfo(err)
		}
		//меркель рут нужен для updblockinfo()
		p.MrklRoot, err = utils.GetMrklroot(p.BinaryData, p.Variables, false)
		if err != nil {
			return utils.ErrInfo(err)
		}
		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

				p.TxHash = utils.Md5(transactionBinaryData)
				log.Debug("p.TxHash", p.TxHash)
				p.TxSlice, err = p.ParseTransaction(&transactionBinaryData)
				log.Debug("p.TxSlice", p.TxSlice)
				if err != nil {
					return utils.ErrInfo(err)
				}

				// txSlice[3] могут подсунуть пустой
				if len(p.TxSlice) > 3 {
					if !utils.CheckInputData(p.TxSlice[3], "int64") {
						return utils.ErrInfo(fmt.Errorf("empty user_id"))
					}
				} else {
					return utils.ErrInfo(fmt.Errorf("empty user_id"))
				}

				// проверим, есть ли такой тип тр-ий
				_, 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)
					return utils.ErrInfo(err_.(error))
				}

				log.Debug("MethodName", MethodName)
				err_ = utils.CallMethod(p, MethodName)
				if _, ok := err_.(error); ok {
					log.Debug("error: %v", err)
					return utils.ErrInfo(err_.(error))
				}

				utils.WriteSelectiveLog("UPDATE transactions SET used=1 WHERE hex(hash) = " + string(utils.Md5(transactionBinaryDataFull)))
				affect, err := p.ExecSqlGetAffect("UPDATE transactions SET used=1 WHERE hex(hash) = ?", utils.Md5(transactionBinaryDataFull))
				if err != nil {
					utils.WriteSelectiveLog(err)
					return utils.ErrInfo(err)
				}
				utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect))

				// даем юзеру понять, что его тр-ия попала в блок
				err = p.ExecSql("UPDATE transactions_status SET block_id = ? WHERE hex(hash) = ?", p.BlockData.BlockId, utils.Md5(transactionBinaryDataFull))
				if err != nil {
					return utils.ErrInfo(err)
				}

				if len(p.BinaryData) == 0 {
					break
				}
			}
		}

		p.UpdBlockInfo()
		p.InsertIntoBlockchain()
	} else {
		return utils.ErrInfo(fmt.Errorf("incorrect type"))
	}

	return nil
}
Exemplo n.º 4
0
/**
фронт. проверка + занесение данных из блока в таблицы и info_block
*/
func (p *Parser) ParseDataFull() error {

	p.TxIds = []string{}
	p.dataPre()
	if p.dataType != 0 { // парсим только блоки
		return utils.ErrInfo(fmt.Errorf("incorrect dataType"))
	}
	var err error

	p.Variables, err = p.GetAllVariables()
	if err != nil {
		return utils.ErrInfo(err)
	}

	//if len(p.BinaryData) > 500000 {
	//	ioutil.WriteFile("block-"+string(utils.DSha256(p.BinaryData)), p.BinaryData, 0644)
	//}

	err = p.ParseBlock()
	if err != nil {
		return utils.ErrInfo(err)
	}

	// проверим данные, указанные в заголовке блока
	err = p.CheckBlockHeader()
	if err != nil {
		return utils.ErrInfo(err)
	}

	utils.WriteSelectiveLog("DELETE FROM transactions WHERE used = 1")
	afect, err := p.ExecSqlGetAffect("DELETE FROM transactions WHERE used = 1")
	if err != nil {
		utils.WriteSelectiveLog(err)
		return utils.ErrInfo(err)
	}
	utils.WriteSelectiveLog("afect: " + utils.Int64ToStr(afect))

	txCounter := make(map[int64]int64)
	p.fullTxBinaryData = p.BinaryData
	var txForRollbackTo []byte
	if len(p.BinaryData) > 0 {
		for {
			// обработка тр-ий может занять много времени, нужно отметиться
			p.UpdDaemonTime(p.GoroutineName)
			p.halfRollback = false
			log.Debug("&p.BinaryData", p.BinaryData)
			transactionSize := utils.DecodeLength(&p.BinaryData)
			if len(p.BinaryData) == 0 {
				return utils.ErrInfo(fmt.Errorf("empty BinaryData"))
			}

			// отчекрыжим одну транзакцию от списка транзакций
			//log.Debug("++p.BinaryData=%x\n", p.BinaryData)
			//log.Debug("transactionSize", transactionSize)
			transactionBinaryData := utils.BytesShift(&p.BinaryData, transactionSize)
			transactionBinaryDataFull := transactionBinaryData
			//ioutil.WriteFile("/tmp/dctx", transactionBinaryDataFull, 0644)
			//ioutil.WriteFile("/tmp/dctxhash", utils.Md5(transactionBinaryDataFull), 0644)
			// добавляем взятую тр-ию в набор тр-ий для RollbackTo, в котором пойдем в обратном порядке
			txForRollbackTo = append(txForRollbackTo, utils.EncodeLengthPlusData(transactionBinaryData)...)
			//log.Debug("transactionBinaryData: %x\n", transactionBinaryData)
			//log.Debug("txForRollbackTo: %x\n", txForRollbackTo)

			err = p.CheckLogTx(transactionBinaryDataFull)
			if err != nil {
				p.RollbackTo(txForRollbackTo, true, false)
				return utils.ErrInfo(err)
			}

			utils.WriteSelectiveLog("UPDATE transactions SET used=1 WHERE hex(hash) = " + string(utils.Md5(transactionBinaryDataFull)))
			affect, err := p.ExecSqlGetAffect("UPDATE transactions SET used=1 WHERE hex(hash) = ?", utils.Md5(transactionBinaryDataFull))
			if err != nil {
				utils.WriteSelectiveLog(err)
				utils.WriteSelectiveLog("RollbackTo")
				p.RollbackTo(txForRollbackTo, true, false)
				return utils.ErrInfo(err)
			}
			utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect))
			//log.Debug("transactionBinaryData", transactionBinaryData)
			p.TxHash = utils.Md5(transactionBinaryData)
			log.Debug("p.TxHash %s", p.TxHash)
			p.TxSlice, err = p.ParseTransaction(&transactionBinaryData)
			log.Debug("p.TxSlice %v", p.TxSlice)
			if err != nil {
				p.RollbackTo(txForRollbackTo, true, false)
				return err
			}

			if p.BlockData.BlockId > 1 {
				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"))
				}
			}

			// время в транзакции не может быть больше, чем на MAX_TX_FORW сек времени блока
			// и  время в транзакции не может быть меньше времени блока -24ч.
			if utils.BytesToInt64(p.TxSlice[2])-consts.MAX_TX_FORW > p.BlockData.Time || utils.BytesToInt64(p.TxSlice[2]) < p.BlockData.Time-consts.MAX_TX_BACK {
				p.RollbackTo(txForRollbackTo, true, false)
				return utils.ErrInfo(fmt.Errorf("incorrect transaction time"))
			}

			// проверим, есть ли такой тип тр-ий
			_, 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.Error("error: %v", err)
				return utils.ErrInfo(err_.(error))
			}

			log.Debug("MethodName", MethodName+"Front")
			err_ = utils.CallMethod(p, MethodName+"Front")
			if _, ok := err_.(error); ok {
				log.Error("error: %v", err_)
				p.RollbackTo(txForRollbackTo, true, false)
				return utils.ErrInfo(err_.(error))
			}

			log.Debug("MethodName", MethodName)
			err_ = utils.CallMethod(p, MethodName)
			if _, ok := err_.(error); ok {
				log.Error("error: %v", err)
				return utils.ErrInfo(err_.(error))
			}

			// даем юзеру понять, что его тр-ия попала в блок
			p.ExecSql("UPDATE transactions_status SET block_id = ? WHERE hex(hash) = ?", p.BlockData.BlockId, utils.Md5(transactionBinaryDataFull))

			// Тут было time(). А значит если бы в цепочке блоков были блоки в которых были бы одинаковые хэши тр-ий, то ParseDataFull вернул бы error
			err = p.InsertInLogTx(transactionBinaryDataFull, utils.BytesToInt64(p.TxMap["time"]))
			if err != nil {
				return utils.ErrInfo(err)
			}

			if len(p.BinaryData) == 0 {
				break
			}
		}
	}

	p.UpdBlockInfo()

	return nil
}