func SubmitWorkRequest(id *uint64, workerName string, jobID string, extraNonce2 string, nTime string, nonce string) *Request {
	return &Request{
		ID:     id,
		Method: Submit,
		Params: []string{workerName, jobID, extraNonce2, nTime, nonce},
	}
}
SubmitWorkRequest creates a submit request message.
package pool
import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"math/big"
	"strings"
	"github.com/decred/dcrd/wire"
	errs "github.com/decred/dcrpool/errors"
)
const (
	UnknownMessage = iota
	RequestMessage
	ResponseMessage
	NotificationMessage
)
const (
	Authorize           = "mining.authorize"
	Subscribe           = "mining.subscribe"
	ExtraNonceSubscribe = "mining.extranonce.subscribe"
	SetDifficulty       = "mining.set_difficulty"
	Notify              = "mining.notify"
	Submit              = "mining.submit"
)
const (
	Unknown            = 20
	StaleJob           = 21
	DuplicateShare     = 22
	LowDifficultyShare = 23
	UnauthorizedWorker = 24
	NotSubscribed      = 25
)
const (
	ExtraNonce2Size = 4
)
type StratumError struct {
	Code      uint32  `json:"code"`
	Message   string  `json:"message"`
	Traceback *string `json:"traceback"`
}
func NewStratumError(code uint32, err error) *StratumError {
	var msg string
	switch code {
	case StaleJob:
		msg = "Stale Job"
	case DuplicateShare:
		msg = "Duplicate share"
	case LowDifficultyShare:
		msg = "Low difficulty share"
	case UnauthorizedWorker:
		msg = "Unauthorized worker"
	case NotSubscribed:
		msg = "Not subscribed"
	case Unknown:
		fallthrough
	default:
		msg = "Other/Unknown"
	}
	if err != nil {
		msg = fmt.Sprintf("%s: %v", msg, err)
	}
	return &StratumError{
		Code:    code,
		Message: msg,
	}
}
func (s *StratumError) MarshalJSON() ([]byte, error) {
	return json.Marshal([]interface{}{s.Code, s.Message, s.Traceback})
}
func (s *StratumError) UnmarshalJSON(p []byte) error {
	var tmp []interface{}
	if err := json.Unmarshal(p, &tmp); err != nil {
		return err
	}
	s.Code = uint32(tmp[0].(float64))
	s.Message = tmp[1].(string)
	if tmp[2] != nil {
		trace := tmp[2].(string)
		s.Traceback = &trace
	}
	return nil
}
func (s *StratumError) String() string {
	return s.Message
}
type Message interface {
	MessageType() int
	String() string
}
type Request struct {
	ID     *uint64     `json:"id"`
	Method string      `json:"method"`
	Params interface{} `json:"params"`
}
func (req *Request) MessageType() int {
	return RequestMessage
}
func (req *Request) String() string {
	b, err := json.Marshal(req)
	if err != nil {
		log.Errorf("unable to marshal request: %v", err)
		return ""
	}
	return string(b)
}
func NewRequest(id *uint64, method string, params interface{}) *Request {
	return &Request{
		ID:     id,
		Method: method,
		Params: params,
	}
}
type Response struct {
	ID     uint64        `json:"id"`
	Error  *StratumError `json:"error"`
	Result interface{}   `json:"result,omitempty"`
}
func (req *Response) String() string {
	b, err := json.Marshal(req)
	if err != nil {
		log.Errorf("unable to marshal response: %v", err)
		return ""
	}
	return string(b)
}
func (req *Response) MessageType() int {
	return ResponseMessage
}
func NewResponse(id uint64, result interface{}, err *StratumError) *Response {
	return &Response{
		ID:     id,
		Error:  err,
		Result: result,
	}
}
func IdentifyMessage(data []byte) (Message, int, error) {
	var req Request
	err := json.Unmarshal(data, &req)
	if err != nil {
		return nil, UnknownMessage, err
	}
	if req.Method != "" {
		if req.ID == nil {
			return &req, NotificationMessage, nil
		}
		return &req, RequestMessage, nil
	}
	var resp Response
	err = json.Unmarshal(data, &resp)
	if err != nil {
		return nil, UnknownMessage, err
	}
	if resp.ID == 0 {
		return nil, UnknownMessage, fmt.Errorf("unable to parse message")
	}
	return &resp, ResponseMessage, nil
}
func AuthorizeRequest(id *uint64, name string, address string) *Request {
	format := "%s.%s"
	if name == "" || address == "" {
		format = "%s%s"
	}
	user := fmt.Sprintf(format, address, name)
	return &Request{
		ID:     id,
		Method: Authorize,
		Params: []string{user, ""},
	}
}
func ParseAuthorizeRequest(req *Request) (string, error) {
	const funcName = "ParseAuthorizeRequest"
	if req.Method != Authorize {
		desc := fmt.Sprintf("%s: request method is not authorize", funcName)
		return "", errs.MsgError(errs.Parse, desc)
	}
	auth, ok := req.Params.([]interface{})
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse authorize parameters",
			funcName)
		return "", errs.MsgError(errs.Parse, desc)
	}
	if len(auth) < 2 {
		desc := fmt.Sprintf("%s: expected 2 params for authorize request, "+
			"got %d", funcName, len(auth))
		return "", errs.MsgError(errs.Parse, desc)
	}
	username, ok := auth[0].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse username parameter "+
			"for authorize request", funcName)
		return "", errs.MsgError(errs.Parse, desc)
	}
	return username, nil
}
func AuthorizeResponse(id uint64, status bool, err *StratumError) *Response {
	return &Response{
		ID:     id,
		Error:  err,
		Result: status,
	}
}
func ParseAuthorizeResponse(resp *Response) (bool, *StratumError, error) {
	const funcName = "ParseAuthorizeResponse"
	status, ok := resp.Result.(bool)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse authorize response "+
			"result parameter", funcName)
		return false, nil, errs.MsgError(errs.Parse, desc)
	}
	return status, resp.Error, nil
}
func SubscribeRequest(id *uint64, userAgent string, notifyID string) *Request {
	params := []string{userAgent}
	if notifyID != "" {
		params = append(params, notifyID)
	}
	return &Request{
		ID:     id,
		Method: Subscribe,
		Params: params,
	}
}
func ParseSubscribeRequest(req *Request) (string, string, error) {
	const funcName = "ParseSubscribeRequest"
	if req.Method != Subscribe {
		desc := fmt.Sprintf("%s: request method is not subscribe", funcName)
		return "", "", errs.MsgError(errs.Parse, desc)
	}
	params, ok := req.Params.([]interface{})
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse subscribe parameters",
			funcName)
		return "", "", errs.MsgError(errs.Parse, desc)
	}
	if len(params) == 0 {
		desc := fmt.Sprintf("%s: no user agent provided for subscribe "+
			"request", funcName)
		return "", "", errs.MsgError(errs.Parse, desc)
	}
	miner, ok := params[0].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse miner parameter for "+
			"subscribe request", funcName)
		return "", "", errs.MsgError(errs.Parse, desc)
	}
	id := ""
	if len(params) == 2 {
		id, ok = params[1].(string)
		if !ok {
			desc := fmt.Sprintf("%s: unable to parse id parameter for "+
				"subscribe request", funcName)
			return "", "", errs.MsgError(errs.Parse, desc)
		}
	}
	return miner, id, nil
}
func SubscribeResponse(id uint64, notifyID string, extraNonce1 string, extraNonce2Size int, err *StratumError) *Response {
	if err != nil {
		return &Response{
			ID:     id,
			Error:  err,
			Result: nil,
		}
	}
	return &Response{
		ID:    id,
		Error: nil,
		Result: []interface{}{[][]string{
			{"mining.set_difficulty", notifyID}, {"mining.notify", notifyID}},
			extraNonce1, extraNonce2Size},
	}
}
func ParseExtraNonceSubscribeRequest(req *Request) error {
	const funcName = "ParseExtraNonceSubscribeRequest"
	if req.Method != ExtraNonceSubscribe {
		desc := fmt.Sprintf("%s: request method is not extra nonce subscribe",
			funcName)
		return errs.MsgError(errs.Parse, desc)
	}
	return nil
}
func ExtraNonceSubscribeResponse(id uint64) *Response {
	return &Response{
		ID:     id,
		Error:  nil,
		Result: false,  
	}
}
func ParseSubscribeResponse(resp *Response) (string, string, uint64, error) {
	const funcName = "ParseSubscribeResponse"
	if resp.Error != nil {
		desc := fmt.Sprintf("%s: %d, %s", funcName, resp.Error.Code,
			resp.Error.Message)
		return "", "", 0, errs.MsgError(errs.Parse, desc)
	}
	res, ok := resp.Result.([]interface{})
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse subscribe response "+
			"result parameter", funcName)
		return "", "", 0, errs.MsgError(errs.Parse, desc)
	}
	ids, ok := res[0].([]interface{})
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse id details", funcName)
		return "", "", 0, errs.MsgError(errs.Parse, desc)
	}
	var nID string
	for _, entry := range ids {
		id, ok := ids[0].(string)
		if ok {
			if id == Notify {
				nID = ids[1].(string)
				break
			}
		}
		idSet, ok := entry.([]interface{})
		if ok {
			id, ok = idSet[0].(string)
			if !ok {
				desc := fmt.Sprintf("%s: unable to parse id", funcName)
				return "", "", 0, errs.MsgError(errs.Parse, desc)
			}
			if id != Notify {
				continue
			}
			nID = idSet[1].(string)
			break
		}
	}
	extraNonce1, ok := res[1].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse subscription ExtraNonce1 "+
			"parameter", funcName)
		return "", "", 0, errs.MsgError(errs.Parse, desc)
	}
	nonce2Size, ok := res[2].(float64)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse subscription "+
			"ExtraNonce2Size parameter", funcName)
		return "", "", 0, errs.MsgError(errs.Parse, desc)
	}
	extraNonce2Size := uint64(nonce2Size)
	return nID, extraNonce1, extraNonce2Size, nil
}
func SetDifficultyNotification(difficulty *big.Rat) *Request {
	diff, _ := difficulty.Float64()
	return &Request{
		Method: SetDifficulty,
		Params: []uint64{uint64(diff)},
	}
}
func ParseSetDifficultyNotification(req *Request) (uint64, error) {
	const funcName = "ParseSetDifficultyNotification"
	if req.Method != SetDifficulty {
		desc := fmt.Sprintf("%s: notification method is not set "+
			"difficulty", funcName)
		return 0, errs.MsgError(errs.Parse, desc)
	}
	params, ok := req.Params.([]interface{})
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse set difficulty "+
			"parameters", funcName)
		return 0, errs.MsgError(errs.Parse, desc)
	}
	return uint64(params[0].(float64)), nil
}
func WorkNotification(jobID string, prevBlock string, genTx1 string, genTx2 string, blockVersion string, nBits string, nTime string, cleanJob bool) *Request {
	return &Request{
		Method: Notify,
		Params: []interface{}{jobID, prevBlock, genTx1, genTx2, []string{},
			blockVersion, nBits, nTime, cleanJob},
	}
}
func ParseWorkNotification(req *Request) (string, string, string, string, string, string, string, bool, error) {
	const funcName = "ParseWorkNotification"
	if req.Method != Notify {
		desc := fmt.Sprintf("%s: notification method is not notify", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	params, ok := req.Params.([]interface{})
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse work notification "+
			"parameters", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	jobID, ok := params[0].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse work notification "+
			"jobID parameter", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	prevBlock, ok := params[1].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse work notification prevBlock "+
			"parameter", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	genTx1, ok := params[2].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse work notification genTx1 "+
			"parameter", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	genTx2, ok := params[3].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse work notification genTx2 "+
			"parameter", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	blockVersion, ok := params[5].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse work notification "+
			"blockVersion parameter", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	nBits, ok := params[6].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse work notification "+
			"nBits parameter", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	nTime, ok := params[7].(string)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse work notification "+
			"nTime parameter", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	cleanJob, ok := params[8].(bool)
	if !ok {
		desc := fmt.Sprintf("%s: unable to parse work notification "+
			"cleanJob parameter", funcName)
		return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
	}
	return jobID, prevBlock, genTx1, genTx2, blockVersion,
		nBits, nTime, cleanJob, nil
}
func GenerateBlockHeader(blockVersionE string, prevBlockE string,
	genTx1E string, extraNonce1E string, genTx2E string) (*wire.BlockHeader, error) {
	const funcName = "GenerateBlockHeader"
	var buf bytes.Buffer
	_, _ = buf.WriteString(blockVersionE)
	_, _ = buf.WriteString(prevBlockE)
	_, _ = buf.WriteString(genTx1E)
	_, _ = buf.WriteString(extraNonce1E)
	_, _ = buf.WriteString(strings.Repeat("0", 56))
	_, _ = buf.WriteString(genTx2E)
	headerE := buf.String()
	headerD, err := hex.DecodeString(headerE)
	if err != nil {
		desc := fmt.Sprintf("%s: unable to decode block header %s: %v",
			funcName, headerE, err)
		return nil, errs.MsgError(errs.Decode, desc)
	}
	var header wire.BlockHeader
	err = header.FromBytes(headerD)
	if err != nil {
		desc := fmt.Sprintf("%s: unable to create header from bytes %s: %v",
			funcName, headerE, err)
		return nil, errs.MsgError(errs.HeaderInvalid, desc)
	}
	return &header, nil
}
func GenerateSolvedBlockHeader(headerE string, extraNonce1E string,
	extraNonce2E string, nTimeE string, nonceE string, miner string) (*wire.BlockHeader, error) {
	headerEB := []byte(headerE)
	switch miner {
	case CPU:
		copy(headerEB[272:280], []byte(nTimeE))
		copy(headerEB[280:288], []byte(nonceE))
		copy(headerEB[288:296], []byte(extraNonce1E))
		copy(headerEB[296:304], []byte(extraNonce2E))
	case ObeliskDCR1:
		nTimeERev, err := hexReversed(nTimeE)
		if err != nil {
			return nil, err
		}
		copy(headerEB[272:280], []byte(nTimeERev))
		nonceERev, err := hexReversed(nonceE)
		if err != nil {
			return nil, err
		}
		copy(headerEB[280:288], []byte(nonceERev))
		copy(headerEB[288:296], []byte(extraNonce1E))
		copy(headerEB[296:304], []byte(extraNonce2E))
	case AntminerDR3, AntminerDR5:
		nTimeERev, err := hexReversed(nTimeE)
		if err != nil {
			return nil, err
		}
		copy(headerEB[272:280], []byte(nTimeERev))
		nonceERev, err := hexReversed(nonceE)
		if err != nil {
			return nil, err
		}
		copy(headerEB[280:288], []byte(nonceERev))
		copy(headerEB[288:312], []byte(extraNonce2E))
	case InnosiliconD9:
		nTimeERev, err := hexReversed(nTimeE)
		if err != nil {
			return nil, err
		}
		copy(headerEB[272:280], []byte(nTimeERev))
		nonceERev, err := hexReversed(nonceE)
		if err != nil {
			return nil, err
		}
		copy(headerEB[280:288], []byte(nonceERev))
		copy(headerEB[288:296], []byte(extraNonce1E))
		copy(headerEB[296:304], []byte(extraNonce2E))
	case WhatsminerD1:
		nTimeERev, err := hexReversed(nTimeE)
		if err != nil {
			return nil, err
		}
		copy(headerEB[272:280], []byte(nTimeERev))
		nonceERev, err := hexReversed(nonceE)
		if err != nil {
			return nil, err
		}
		copy(headerEB[280:288], []byte(nonceERev))
		copy(headerEB[288:304], []byte(extraNonce2E))
	default:
		desc := fmt.Sprintf("miner %s is unknown", miner)
		return nil, errs.MsgError(errs.MinerUnknown, desc)
	}
	solvedHeaderD, err := hex.DecodeString(string(headerEB))
	if err != nil {
		desc := fmt.Sprintf("%s: unable to decode solved header: %v",
			miner, err)
		return nil, errs.MsgError(errs.Decode, desc)
	}
	var solvedHeader wire.BlockHeader
	err = solvedHeader.FromBytes(solvedHeaderD)
	if err != nil {
		desc := fmt.Sprintf("%s: unable to create header from bytes: %v",
			miner, err)
		return nil, errs.MsgError(errs.Parse, desc)
	}
	return &solvedHeader, nil
}