package alph

import (
	"bytes"
	"database/sql"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"net"
	"strconv"
	"sync"
	"sync/atomic"

	//"pool/internal/cache"
	"pool/internal/db"
	"pool/internal/gbt/alph/constants"
	"pool/internal/gbt/coin"
	"pool/internal/gbt/dbif"
	"pool/internal/msg"
	"pool/internal/utility"
	"time"

	//"github.com/btcsuite/btcd/rpcclient"
	_ "github.com/mattn/go-sqlite3"

	"go.uber.org/zap"
)

const GBT_ALPH_VERSION = "alph v1.0"
const headerSize = 4

type AlphAddrConfig struct {
	Addr string `json:"addr"`
}

type AlphConfig struct {
	Alph AlphAddrConfig `json:"alph"`
}

type GbtAlphContext struct {
	Config AlphConfig
	GbtCtx *coin.GbtContext

	last_time      time.Time
	last_gbt       BlockAlphMsg
	last_blockhash string

	last_height uint32

	Submits float64

	addressIndex int

	Target          []byte
	Header          []byte
	last_body       string
	ChainIndex      int // 分片
	new_block_chan  chan int
	new_block_index int
}

type BlockAlphMsg struct {
	Jobs []AlphBlockMsg
}

type AlphBlockMsg struct {
	JobId      string
	FromGroup  uint32
	ToGroup    uint32
	Height     uint32
	HeaderBlob string
	TargetBlob string
	TxsBlob    string
}

type ReceiveJob struct {
	FromGroup        uint32
	ToGroup          uint32
	HeaderBlobLength uint32
	HeaderBlob       []byte
	TxsBlobLength    uint32
	TxsBlob          []byte
	TargetLength     uint32
	TargetBlob       []byte
	Height           uint32
	DataLength       uint32
}

type JobCounter struct {
	counter uint64
	mu      sync.Mutex
}

var logg *zap.Logger
var GbtAlphCtx GbtAlphContext

type GbtAlphMsg struct {
	Id               uint64 `json:"id"`
	HeaderCommitment string `json:"headerCommitment"` // 获取到的任务的区块头
	NBits            string `json:"nBits"`
}

type GetBlockHeaderMsg struct {
	Height        int    `json:"height"`
	Nonce         string `json:"nonce"`
	Confirmations int    `json:"confirmations"`
}

type GetBlockStatsMsg struct {
	Height   int     `json:"height"`
	Subsidy  float64 `json:"subsidy"`
	Totalfee float64 `json:"totalfee"`
}

type BlockCheckData struct {
	FromGroup uint32
	ToGroup   uint32
	Height    int
	Nonce     string
	User      string
	Miner     string
	MinerId   string
	Hash      string
	SubIdx    int
}

type PushBlkNewMsg struct {
	Coin   string `json:"coin"`
	Height int    `json:"height"`
	Nonce  string `json:"nonce"`
}

var addr = []string{
	"1CYKPymfTVex9KZ2i48S3v5cAE7xT6hERG1P6GJiHgWJu",
	"14eEDF5SvnYcz12Cmkn9UJHLiiTKcqvaP2JgbsSevc38H",
	"1HLvickKHvsFziGqmZt7hcithAtRkgueUBHXRHBvMSp98",
	"1JBHWv4XPbagWxnC9HXimz67MY85KoKz3h16uvk3cJcAS",
}

func stringToFloat64(str string) float64 {
	floatValue, err := strconv.ParseFloat(str, 64)
	if err != nil {
		fmt.Println("转换失败:", err)
		return 0
	}
	return floatValue
}

func savePoint4(num float64) float64 {
	result := fmt.Sprintf("%.4f", num)
	return stringToFloat64(result)
}
func update_block_confirm(gbt *GbtAlphContext) {
	// 1,每次报块都调用本函数
	// 2,先查出报块时的上两个块，然后查询这些快是否在主链上(通过区块的hash传入CheckBlk函数)
	// 3,通过查询区块信息，确定区块的nonce、height、奖励，通过链信息，查询出当前链高度
	db, err := sql.Open("sqlite3", "./blocks.db")
	if err != nil {
		//log.Printf("Error opening database: %v", err)
		logg.Error("[gbt]", zap.String("Error opening database", err.Error()))
		return
	}
	defer db.Close()

	query := "SELECT fromgroup, togroup, user, miner, minerid, height, nonce, hash, subidx FROM blocks WHERE checked=0 AND created_at >= datetime('now', '-30 minutes') order by id desc limit 1"
	rows, err := db.Query(query)
	if err != nil {
		//log.Printf("Error executing query from blocks: %v", err)
		logg.Error("[gbt]", zap.String("Error executing query from blocks:", err.Error()))
		return
	}
	defer rows.Close()

	var blocks []BlockCheckData
	for rows.Next() {
		var fromGroup uint32
		var toGroup uint32
		var height int
		var user string
		var miner string
		var minerid string
		var hash string
		var subidx int
		var nonce string
		if err := rows.Scan(&fromGroup, &toGroup, &user, &miner, &minerid, &height, &nonce, &hash, &subidx); err != nil {
			//log.Printf("Error scanning row in blocks: %v", err)
			logg.Error("[gbt]", zap.String("Error scanning row in blocks:", err.Error()))
			return
		}
		var blockdata BlockCheckData
		blockdata.FromGroup = fromGroup
		blockdata.ToGroup = toGroup
		blockdata.Height = height
		blockdata.User = user
		blockdata.Miner = miner
		blockdata.MinerId = minerid
		blockdata.Hash = hash
		blockdata.SubIdx = subidx
		blockdata.Nonce = nonce
		blocks = append(blocks, blockdata)
	}
	fmt.Println("blocks:", blocks)
	for _, block := range blocks {
		blockHash, err := gbt.GbtCtx.ClientAlphApi.GetBlockHash(block.FromGroup, block.ToGroup, uint32(block.Height))
		if err != nil {
			logg.Info("[gbt]", zap.String("GetBlockHash ", err.Error()))
			continue
		}
		if blockHash == block.Hash {
			checkResult := gbt.GbtCtx.ClientAlphApi.CheckBlk(blockHash)
			if checkResult {
				blockInfo := gbt.GbtCtx.ClientAlphApi.GetBlcokInfo(blockHash)
				var total_amount float64 = 0
				fromGroup, toGroup, nonce, height, input, output := blockInfo.ChainFrom, blockInfo.ChainTo, blockInfo.Nonce, blockInfo.Height, blockInfo.Transactions[len(blockInfo.Transactions)-1].Unsigned.Inputs, blockInfo.Transactions[len(blockInfo.Transactions)-1].Unsigned.FixedOutputs
				if len(input) == 0 {
					for v := range output {
						address, amount := output[v].Address, output[v].AttoAlphAmount
						if address == addr[fromGroup] && nonce == block.Nonce {
							total_amount += savePoint4(stringToFloat64(amount) / math.Pow(10, 18))
							fmt.Println(fromGroup, "->", toGroup, "(", height, ")：", total_amount, ",", nonce, " ", blockHash, " ", address, " 报块成功")
						} else {
							fmt.Println(fromGroup, "->", toGroup, "(", height, ")：", total_amount, ",", nonce, "不是报块，实际报块地址为：", address)
						}
					}
				}
				block_height := int64(block.Height)
				dbif.AlphNotifyPoolBlkStatsSuccess(gbt.GbtCtx, uint32(fromGroup), uint32(toGroup), block_height, "", block.Nonce, int64(block.SubIdx), total_amount, 0)
				dbif.NotifyAlphBlkDetailSuccess(gbt.GbtCtx, uint32(fromGroup), uint32(toGroup), block_height, "", block.Nonce, int64(block.SubIdx))
				dbif.NotifyAlphBlkNewDb(gbt.GbtCtx, uint32(fromGroup), uint32(toGroup), block_height, block.Hash, true, block.Nonce, int64(block.SubIdx))

				updateSQL := `UPDATE blocks SET checked = 1 WHERE height = ? AND nonce = ? AND checked = 0`
				_, err = db.Exec(updateSQL, block.Height, block.Nonce)
				if err != nil {
					logg.Error("[gbt]", zap.String("Error updating blk_new:", err.Error()))
					continue
				}
				logg.Warn("[gbt]", zap.String("update block success:", fmt.Sprint(block.Height)+" "+block.Nonce))
			}
		} else {
			logg.Info("[gbt]", zap.String("GetBlockHash ", "区块hash不在主链上"))
		}
	}
}

func NewAlphPool(host string, port string) (*net.Conn, error) {
	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%s", host, port))
	if err != nil {
		return nil, fmt.Errorf("failed to connect to mining pool: %w", err)
	}
	return &conn, nil
}

func processJob(data []byte) (*ReceiveJob, error) {
	reader := bytes.NewReader(data)
	var job ReceiveJob

	// Read fixed fields
	fields := []interface{}{
		&job.FromGroup, &job.ToGroup, &job.HeaderBlobLength,
	}
	for _, field := range fields {
		if err := binary.Read(reader, binary.BigEndian, field); err != nil {
			return nil, fmt.Errorf("failed to read fixed field: %w", err)
		}
	}

	// Read variable-length fields
	job.HeaderBlob = make([]byte, job.HeaderBlobLength)
	if _, err := io.ReadFull(reader, job.HeaderBlob); err != nil {
		return nil, fmt.Errorf("failed to read HeaderBlob: %w", err)
	}

	fields = []interface{}{
		&job.TxsBlobLength,
	}
	for _, field := range fields {
		if err := binary.Read(reader, binary.BigEndian, field); err != nil {
			return nil, fmt.Errorf("failed to read fixed field: %w", err)
		}
	}

	job.TxsBlob = make([]byte, job.TxsBlobLength)
	if _, err := io.ReadFull(reader, job.TxsBlob); err != nil {
		return nil, fmt.Errorf("failed to read TxsBlob: %w", err)
	}

	fields = []interface{}{
		&job.TargetLength,
	}
	for _, field := range fields {
		if err := binary.Read(reader, binary.BigEndian, field); err != nil {
			return nil, fmt.Errorf("failed to read fixed field: %w", err)
		}
	}

	job.TargetBlob = make([]byte, job.TargetLength)
	if _, err := io.ReadFull(reader, job.TargetBlob); err != nil {
		return nil, fmt.Errorf("failed to read TargetBlob: %w", err)
	}

	if err := binary.Read(reader, binary.BigEndian, &job.Height); err != nil {
		return nil, fmt.Errorf("failed to read Height: %w", err)
	}

	job.DataLength = uint32(len(data) - reader.Len())
	return &job, nil
}

func _parseJobs(message []byte) ([]ReceiveJob, error) {
	jobCount := binary.BigEndian.Uint32(message[:4])
	var jobs []ReceiveJob
	offset := 4
	for i := uint32(0); i < jobCount; i++ {
		if offset >= len(message) {
			return nil, fmt.Errorf("insufficient data for job parsing")
		}
		job, err := processJob(message[offset:])
		if err != nil {
			return nil, fmt.Errorf("error processing job: %w", err)
		}
		jobs = append(jobs, *job)
		offset += int(job.DataLength)
	}
	return jobs, nil
}

type SubmitResult struct {
	FromGroup uint32
	ToGroup   uint32
	BlockHash []byte
	Successed bool
}

func _parseSubmitResult(buffer []byte) (SubmitResult, error) {
	if len(buffer) < 41 {
		return SubmitResult{}, fmt.Errorf("buffer length is too short: %d", len(buffer))
	}

	fromGroup := binary.BigEndian.Uint32(buffer[0:4])
	toGroup := binary.BigEndian.Uint32(buffer[4:8])
	blockHash := buffer[8:40]
	successed := buffer[40] == 1
	new_block_notify := successed
	if new_block_notify {
		update_block_confirm(&GbtAlphCtx)
	}
	// fmt.Println("节点返回的hash：", blockHash)
	// fmt.Println("节点返回的结果：", successed)
	return SubmitResult{
		FromGroup: fromGroup,
		ToGroup:   toGroup,
		BlockHash: blockHash,
		Successed: successed,
	}, nil
}

func ParseJobs(data []byte) (interface{}, error) {
	if len(data) < headerSize+1 {
		return nil, fmt.Errorf("data too short to contain a valid job")
	}

	reader := bytes.NewReader(data)
	var bodyLength uint32
	if err := binary.Read(reader, binary.BigEndian, &bodyLength); err != nil {
		return nil, fmt.Errorf("failed to read body length: %w", err)
	}

	version := uint8(data[headerSize])
	if version != constants.MiningProtocolVersion {
		return nil, fmt.Errorf("通信协议版本号错误！")
	}
	messageType := uint8(data[headerSize+1])
	// statOffset := headerSize + 2
	// endOffset := headerSize + bodyLength
	message := data[headerSize+2 : headerSize+bodyLength] // startOffset : endOffset
	if len(message) < 4 {
		return nil, fmt.Errorf("message too short to parse job size")
	}
	var result interface{}
	var err error
	if messageType == constants.JobsMessageType {
		result, err = _parseJobs(message)
		if err != nil {
			return nil, fmt.Errorf("解析任务失败: %w", err)
		}
		return result.([]ReceiveJob), nil
	} else if messageType == constants.SubmitResultMessageType {
		result, err = _parseSubmitResult(message)
		if err != nil {
			return nil, fmt.Errorf("解析提交结果失败: %w", err)
		}
		return result.(SubmitResult), nil
	} else {
		return nil, fmt.Errorf("未知消息类型: %d", messageType)
	}

}

func NewJobCounter() *JobCounter {
	return &JobCounter{}
}

// JobCounter 增加计数器并返回当前计数器值的十六进制表示
func (jc *JobCounter) Next() string {
	jc.mu.Lock()
	defer jc.mu.Unlock()

	// 增加计数器
	jc.counter++

	// 当计数器达到 65535 时重置为 1
	if jc.counter >= 0xFFFF {
		jc.counter = 1
	}

	return jc.Current()
}

// 返回当前计数器值的十六进制表示
func (jc *JobCounter) Current() string {
	return fmt.Sprintf("%x", jc.counter)
}

var jobCounter = NewJobCounter() // 创建一个全局唯一的JobCounter实例

func gbt_running(gbt *GbtAlphContext) {
	fmt.Println("gbt_running started")
	var lastBuffer []byte
	var buffer = make([]byte, 5800)
	for {
		if !gbt.GbtCtx.Started {
			break
		}
		n, err := (*gbt.GbtCtx.ClientAlph).Read(buffer)
		if err != nil {
			logg.Error("Error reading message", zap.Error(err))
			break
		}
		message := append(lastBuffer, buffer[:n]...)

		for len(message) >= headerSize {
			if len(message) < headerSize {
				break
			}
			bodyLength := binary.BigEndian.Uint32(message[:headerSize])
			totalLength := headerSize + int(bodyLength)
			if len(message) < totalLength {
				break
			}
			completeMessage := message[:totalLength]
			processMessage(completeMessage, gbt)
			message = message[totalLength:]
		}
		lastBuffer = message
	}
}
func get_gbt_msg(gbt *GbtAlphContext, gbtmsg []byte) {
	if !gbt.GbtCtx.Started {
		return
	}
	// new_block_notify := false

	if gbtmsg != nil {
		//check_preblock(gbt, DbCtx)
		if gbt.GbtCtx.PubCh == nil {
			gbt.GbtCtx.PubCh = utility.InitZmqPub(gbt.GbtCtx.Config.Zmq.Pub)
		}
		if gbt.GbtCtx.PubCh != nil {
			for trycnt := 0; trycnt < 3; trycnt++ {
				err := gbt.GbtCtx.PubCh.SendMessage([][]byte{[]byte("jobalph"), gbtmsg})
				if err != nil {
					logg.Warn("[gbt]", zap.String("job ", err.Error()))
					continue
				} else {
					//gbt.GbtCtx.PubCh.SendChan <- [][]byte{[]byte("jobnexa"), gbtmsg}
					logg.Warn("[gbt]", zap.String("job ", "sent"))
					break
				}
			}
			//gbt.GbtCtx.AlivingChan <- true
			atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
		} else {
			logg.Warn("[gbt]", zap.String("job ", "sent failed! PubCh nil"))
		}
	} else {
		atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
	}

	// if new_block_notify {
	// 	update_block_confirm(gbt)
	// }
	// }
}

// 重置定时器
// func resetTimer(timer *time.Timer, timeout int) {
// 	if !timer.Stop() {
// 		<-timer.C
// 	}
// 	timer.Reset(time.Duration(timeout) * time.Millisecond)
// }

// 处理接收到的完整消息
func processMessage(message []byte, gbt *GbtAlphContext) {
	jobs, err := ParseJobs(message)
	if err != nil {
		logg.Error("Error parsing jobs", zap.Error(err))
		return
	}

	switch job := jobs.(type) {
	case []ReceiveJob:
		handleReceiveJobs(job, gbt)
	case SubmitResult:
		fmt.Println("job type：", job.Successed)
		handleSubmitResult(job)
	default:
		logg.Warn("Unexpected message type")
	}
}

// var jobIndex int = 0

// 处理接收到的任务
func handleReceiveJobs(jobs []ReceiveJob, gbt *GbtAlphContext) {
	// for _, job := range jobs {
	jobId := jobCounter.Next()
	// 	block := AlphBlockMsg{
	// 		JobId:     jobId,
	// 		FromGroup: job.FromGroup,
	// 		ToGroup:   job.ToGroup,
	// 		Height:    job.Height,
	// 		Header:    fmt.Sprintf("%x", job.HeaderBlob),
	// 		Target:    fmt.Sprintf("%x", job.TargetBlob),
	// 		Txs:       fmt.Sprintf("%x", job.TxsBlob),
	// 	}
	// 	alphJobs.Jobs = append(alphJobs.Jobs, block)
	// }
	// index := rand.Intn(16)
	// 0-0 0-1 0-2 0-3 | 0 1 2 3
	// 1-0 1-1 1-2 1-3 | 4 5 6 7
	// 2-0 2-1 2-2 2-3 | 8 9 10 11
	// 3-0 3-1 3-2 3-3 | 12 13 14 15
	index := 0
	jobId, FromGroup, ToGroup, Height, Header, Target, Txs := jobId, jobs[index].FromGroup, jobs[index].ToGroup, jobs[index].Height, jobs[index].HeaderBlob, jobs[index].TargetBlob, jobs[index].TxsBlob
	job := AlphBlockMsg{
		JobId:      jobId,
		FromGroup:  FromGroup,
		ToGroup:    ToGroup,
		Height:     Height,
		HeaderBlob: fmt.Sprintf("%x", Header),
		TargetBlob: fmt.Sprintf("%x", Target),
		TxsBlob:    fmt.Sprintf("%x", Txs),
	}
	// fmt.Println("接到新任务：", job.JobId, job.TargetBlob)
	data, err := json.Marshal(job)
	if err != nil {
		logg.Error("Error marshaling job", zap.Error(err))
		return
	}
	// jobIndex += 1
	// fmt.Println("gbt获取任务时间：", time.Now(), "\t", "gbt获取任务序号：", jobIndex)
	get_gbt_msg(gbt, data)
	// }
}

// 处理提交区块的结果
func handleSubmitResult(result SubmitResult) {
	fromGroup, toGroup := result.FromGroup, result.ToGroup
	hash := utility.BytesToHexStr(result.BlockHash)
	chainIndex := utility.ChainIndexStr(fromGroup, toGroup)
	// fmt.Println("报块上链：", chainIndex, "：", hash)
	if result.Successed {
		logg.Info("Block submitted successfully", zap.String("hash", hash), zap.String("chainIndex", chainIndex))
	} else {
		logg.Error("Block submission failed", zap.String("hash", hash), zap.String("chainIndex", chainIndex))
	}
}

func gbt_notify_running(gbt *GbtAlphContext) {
	for {
		if !gbt.GbtCtx.Started {
			break
		}

		if gbt.GbtCtx.NodeSubCh == nil {
			gbt.GbtCtx.NodeSubCh = utility.InitZmqSub(gbt.GbtCtx.Config.Rpc.ZmqSub, utility.BITCOIND_ZMQ_HASHBLOCK)
		}
		if gbt.GbtCtx.NodeSubCh != nil {
			cmsg_sub, err := gbt.GbtCtx.NodeSubCh.RecvMessage()

			if err != nil {
				if !gbt.GbtCtx.Started {
					break
				}
				gbt.GbtCtx.NodeSubCh.SetSubscribe(utility.BITCOIND_ZMQ_HASHBLOCK)
				gbt.GbtCtx.NodeSubCh.Connect(gbt.GbtCtx.Config.Rpc.ZmqSub)
				continue
			}
			if len(cmsg_sub) >= 2 {
				if string(cmsg_sub[0]) == "hashblock" {
					GbtAlphCtx.new_block_index = GbtAlphCtx.new_block_index + 1
					gbt.new_block_chan <- GbtAlphCtx.new_block_index

				}
			}
		} else {
			logg.Error("[gbt]", zap.String("notify", "NodeSubCh fail!"))
			time.Sleep(time.Duration(1) * time.Second)
		}
	}
}

func alphInit(config *AlphConfig) {
	data, err := ioutil.ReadFile("gbt.conf")
	if err != nil {
		panic(err.Error())
	}
	if err = json.Unmarshal(data, &config); err != nil {
		panic(err.Error())
	}
}
func Init(GbtCtx *coin.GbtContext, DbCtx *db.DbContext) {
	GbtAlphCtx.GbtCtx = GbtCtx

	GbtAlphCtx.last_height = 0

	alphInit(&GbtAlphCtx.Config)

	GbtAlphCtx.Target = make([]byte, 32)
	GbtAlphCtx.Header = make([]byte, 49)
	GbtAlphCtx.last_time = time.Now()
	logg = GbtCtx.Log
	GbtAlphCtx.new_block_chan = make(chan int, 256)
	GbtAlphCtx.new_block_index = 0
}

func Start() {
	go gbt_running(&GbtAlphCtx)
	// go gbt_notify_running(&GbtAlphCtx)
	go submit_block_running(&GbtAlphCtx)
}

func Stop() {
	defer close(GbtAlphCtx.new_block_chan)
}

func new_block_into_db(block *GbtAlphContext, user string, miner string, minerid string, fromGroup int, toGroup int, height int64, nonce string, hash string, subidx int64) bool {
	db, err := sql.Open("sqlite3", "./blocks.db")
	if err != nil {
		log.Printf("Error opening database: %v", err)
		return false
	}
	defer db.Close()

	createTableSQL := `
					CREATE TABLE IF NOT EXISTS blocks (
					  	id INTEGER PRIMARY KEY AUTOINCREMENT,
						user TEXT NOT NULL,
						miner TEXT NOT NULL,
						minerid TEXT NOT NULL,
						fromGroup INTEGER NOT NULL,
						toGroup INTEGER NOT NULL,
					  	height INTEGER,
						nonce TEXT NOT NULL,
						hash TEXT NOT NULL,
						subidx INTEGER,
					  	checked INTEGER,
					created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
					  );`
	_, err = db.Exec(createTableSQL)
	if err != nil {
		log.Printf("Error creating table: %v", err)
		return false
	}

	insertSQL := `INSERT INTO blocks (user, miner, minerid, fromGroup, toGroup, height, nonce, hash, checked, subidx) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
	_, err = db.Exec(insertSQL, user, miner, minerid, fromGroup, toGroup, height, nonce, hash, 0, subidx)
	if err != nil {
		log.Printf("Error inserting data from blocks %s: %v", fmt.Sprint(height), err)
		return false
	}
	return true
}

func submitToChain(gbt *GbtAlphContext, block []byte) error {
	blockSize := len(block)
	msgPrefixSize := 1 + 1 + 4
	msgSize := msgPrefixSize + blockSize
	msgHeader := make([]byte, 10)
	binary.BigEndian.PutUint32(msgHeader[0:4], uint32(msgSize))
	msgHeader[4] = constants.MiningProtocolVersion
	msgHeader[5] = constants.SubmitBlockMessageType
	binary.BigEndian.PutUint32(msgHeader[6:10], uint32(blockSize))

	data := bytes.Join([][]byte{msgHeader, block}, nil)
	_, err := (*gbt.GbtCtx.ClientAlph).Write(data)
	return err
}

func submit_block_running(block *GbtAlphContext) {
	logg.Info("[block]", zap.String("submit_block_running", "Start."))
	for {
		if !block.GbtCtx.Started {
			break
		}
		if block.GbtCtx.SubCh == nil {
			block.GbtCtx.SubCh = utility.InitZmqSub(block.GbtCtx.Config.Zmq.Sub, "blk"+block.GbtCtx.Coin)
		}
		if block.GbtCtx.SubCh != nil {
			cmsg_sub, err := block.GbtCtx.SubCh.RecvMessage() // [ []byte("topic"), []byte("message") ]
			if err != nil {
				if !block.GbtCtx.Started {
					break
				}
				time.Sleep(time.Duration(1) * time.Second)

				block.GbtCtx.SubCh.SetSubscribe("blk" + block.GbtCtx.Coin)
				block.GbtCtx.SubCh.Connect(block.GbtCtx.Config.Zmq.Sub)
				continue
			}

			if len(cmsg_sub) >= 2 {
				if string(cmsg_sub[0]) == "blkalph" {
					cmsg := cmsg_sub[1] // [(区块结构, xbyte), (heightBlob, 8byte), (indexB, 8byte)]
					// [(0 - cmsg长度-16), (最后16 - 8 byte),   (最后 7-0 byte)]

					//block data
					msgb := make([]byte, len(cmsg)-16)
					copy(msgb, cmsg)

					//height
					heightb, err := hex.DecodeString(string(cmsg[len(msgb) : len(msgb)+8])) // heightb 8bytes
					if err != nil {

						logg.Error("[block]", zap.String("failed to decode height", err.Error()))
						continue
					}
					var height uint32 = utility.ByteToUint32(heightb)
					logg.Warn("[block]", zap.Uint32("height", height))

					if height <= block.last_height {
						continue
					}
					block.last_height = height

					//index
					indexb, err1 := hex.DecodeString(string(cmsg[len(msgb)+8:])) // indexb 8bytes
					if err1 != nil {
						//block.Consumer.MarkOffset(cmsg, "")
						logg.Error("[block]", zap.String("failed to decode index", err1.Error()))
						continue
					}
					//copy(indexb, cmsg.Value[len(msgb)+4:])
					var index uint32 = utility.ByteToUint32(indexb)
					logg.Warn("[block]", zap.Uint32("index", index))
					logg.Debug("[block]", zap.String("msg", string(cmsg)), zap.String("blk", string(msgb)))

					var alphblock msg.BlockAlphMsg

					if err := json.Unmarshal(msgb, &alphblock); err != nil {
						//block.Consumer.MarkOffset(cmsg, "")
						logg.Error("[block]", zap.String("failed to Unmarshal job", err.Error()))
						continue
					}
					var nonceBytes, headerBytes, txsBytes []byte
					if alphblock.Txs != "" {
						nonceBytes, headerBytes, txsBytes = utility.HexStrToBytes(alphblock.Nonce), utility.HexStrToBytes(alphblock.Header), utility.HexStrToBytes(alphblock.Txs)
					} else {
						nonceBytes, headerBytes, txsBytes = utility.HexStrToBytes(alphblock.Nonce), utility.HexStrToBytes(alphblock.Header), []byte{0x00}
					}

					blk := bytes.Join([][]byte{nonceBytes, headerBytes, txsBytes}, nil) // blk:= nonceBytes + headerBytes + txsBytes
					// rawmsgs := make([]json.RawMessage, 1)
					logg.Info("[block]", zap.String("blk", fmt.Sprintf("%x", blk)))

					err2 := submitToChain(block, blk) // 将报块提交到链上
					if err2 != nil {
						logg.Error("[block]", zap.String("提交报块失败：", err2.Error()))
					}

					// result, err := block.GbtCtx.Client.RawRequest("submitminingsolution", rawmsgs)
					// if err != nil {
					// 	logg.Error("[block]", zap.String("submitminingsolution", err.Error()))
					// } else {
					// 	//last_result = result
					// }

					dbif.NotifyAlphPoolBlkStatsSubmitResult(block.GbtCtx, alphblock.FromGroup, alphblock.ToGroup, int64(height), alphblock.Hash, alphblock.Nonce, alphblock.SubIdx)

					block.Submits += 1

					logg.Warn("[block]", zap.Float64("total submits", block.Submits), zap.Int64("SubIdx", alphblock.SubIdx))

					new_block_into_db(block, alphblock.User, alphblock.Miner, alphblock.Index, int(alphblock.FromGroup), int(alphblock.ToGroup), int64(height), alphblock.Nonce, alphblock.Hash, alphblock.SubIdx)
				}
			}
		} else {
			logg.Error("[block]", zap.String("block", "SubCh failed! retry"))
			time.Sleep(time.Duration(1) * time.Second)
		}
	}
}
