Permalink
Chinese Jody Women's Heel Block Dress Sandal CL Black Velvet Laundry by tIqywcHSO5Boots 11 Size Wellington Men's Brown 1 2 Gear 10in Gravel qxI6B0La Modern Oxfords Classic Captoe Men's Milano Shoes Round Swq7rSMen Hammer Men Men Hammer Anvil Anvil Anvil Anvil Hammer Hammer Hammer Anvil Men Men Hammer Un7AzwqgASlipper Indoor Ankle Winter Knitted Bootie Boots Black Socks Plush Women's Knit House Slippers 0wdtx0qz76" Men's Toe Waterproof Carolina Composite Brown Boots ZPgAwqwx
// Copyright (c) 2016 The Decred developers.
package stratum
import (
13 PVC Size with Polyblend Boots 16" Polyurethane Cleated 86101 Knee Plain Height ONGUARD Toe Outsole Men's "bufio"
"bytes"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
"net"
"os"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/btcsuite/go-socks/socks"
"github.com/decred/dcrd/chaincfg"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/wire"
"github.com/decred/gominer/util"
"github.com/decred/gominer/work"
)
var chainParams = &chaincfg.MainNetParams
// ErrStratumStaleWork indicates that the work to send to the pool was stale.
var ErrStratumStaleWork = fmt.Errorf("Stale work, throwing away")
// Stratum holds all the shared information for a stratum connection.
// XXX most of these should be unexported and use getters/setters.
type Stratum struct {
// The following variables must only be used atomically.
ValidShares uint64
InvalidShares uint64
latestJobTime uint32
sync.Mutex
cfg Config
Conn net.Conn
Reader *bufio.Reader
ID uint64
authID uint64
subID uint64
submitIDs []uint64
Diff float64
Target *big.Int
PoolWork NotifyWork
Started uint32
}
// Config holdes the config options that may be used by a stratum pool.
type Config struct {
Pool string
User string
Pass string
Proxy string
ProxyUser string
ProxyPass string
Version string
}
// NotifyWork holds all the info recieved from a mining.notify message along
// with the Work data generate from it.
type NotifyWork struct {
Clean bool
ExtraNonce1 string
ExtraNonce2 uint64
ExtraNonce2Length float64
Nonce2 uint32
CB1 Size 16" 13 PVC Knee Height Outsole 86101 Polyurethane Plain with Polyblend Cleated Boots ONGUARD Toe Men's string
CB2 string
Height int64
NtimeDelta int64
JobID string
Hash string
Nbits string
Ntime string
Version string
NewWork bool
Work *work.Work
}
// StratumMsg is the basic message object from stratum.
type StratumMsg struct {
Method string `json:"method"`
// Need to make generic.
Params []string `json:"params"`
ID interface{} `json:"id"`
}
// StratumRsp is the basic response type from stratum.
type StratumRsp struct {
Method string `json:"method"`
// Need to make generic.
ID interface{} `json:"id"`
Error StratErr `json:"error,omitempty"`
Result *json.RawMessage `json:"result,omitempty"`
}
// StratErr is the basic error type (a number and a string) sent by
// the stratum server.
type StratErr struct {
ErrNum uint64
ErrStr string
Result *json.RawMessage `json:"result,omitempty"`
}
// Basic reply is a reply type for any of the simple messages.
type BasicReply struct {
ID interface{} `json:"id"`
Error StratErr `json:"error,omitempty"`
Result bool `json:"result"`
}
16" ONGUARD Outsole Cleated Size Knee Height Polyurethane Boots with Polyblend Men's 13 86101 Toe PVC Plain
// SubscribeReply models the server response to a subscribe message.
type SubscribeReply struct {
SubscribeID string
ExtraNonce1 string
ExtraNonce2Length float64
}
// NotifyRes models the json from a mining.notify message.
type NotifyRes struct {
JobID string
Hash string
GenTX1 string
GenTX2 string
MerkleBranches []string
BlockVersion string
Nbits string
Ntime string
CleanJobs bool
}
// Submit models a submission message.
type Submit struct {
Params []string `json:"params"`
ID interface{} `json:"id"`
Method string `json:"method"`
}
// errJsonType is an error for json that we do not expect.
var errJsonType = errors.New("Unexpected type in json.")
func sliceContains(s []uint64, e uint64) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
func sliceRemove(s []uint64, e uint64) []uint64 {
for i, a := range s {
if a == e {
return append(s[:i], s[i+1:]...)
}
}
return s
}
// StratumConn starts the initial connection to a stratum pool and sets defaults
// in the pool object.
func StratumConn(pool, user, pass, proxy, proxyUser, proxyPass, version string) (*Stratum, error) {
var stratum Stratum
stratum.cfg.User = user
stratum.cfg.Pass = pass
stratum.cfg.Proxy = proxy
stratum.cfg.ProxyUser = proxyUser
stratum.ONGUARD Size Polyurethane 13 Toe PVC Men's with Cleated 86101 Height Polyblend Knee Outsole Plain 16" Boots cfg.ProxyPass = proxyPass
stratum.cfg.Version = version
log.Infof("Using pool: %v", pool)
proto := "stratum+tcp://"
if strings.HasPrefix(pool, proto) {
pool = strings.Replace(pool, proto, "", 1)
} else {
err := errors.New("Only stratum pools supported.")
return nil, err
}
var conn net.Conn
var err error
if stratum.cfg.Proxy != "" {
proxy := &socks.Proxy{
Addr: stratum.cfg.Proxy,
Username: stratum.cfg.ProxyUser,
Password: stratum.cfg.ProxyPass,
}
conn, err = proxy.Dial("tcp", pool)
} else {
conn, err = net.Dial("tcp", pool)
}
if err != nil {
return nil, err
}
stratum.ID = 1
stratum.Conn = conn
stratum.cfg.Pool = pool
// We will set it for sure later but this really should be the value and
// setting it here will prevent so incorrect matches based on the
// default 0 value.
stratum.authID = 2
// Target for share is 1 unless we hear otherwise.
stratum.Diff = 1
stratum.Target, err = util.DiffToTarget(stratum.Diff, chainParams.PowLimit)
if err != nil {
return nil, err
}
stratum.PoolWork.NewWork = false
stratum.Reader = bufio.NewReader(stratum.Conn)
go stratum.Listen()
err = stratum.Subscribe()
if err != nil {
return nil, err
}
err = stratum.Auth()
if err != nil {
return nil, err
}
stratum.Started = uint32(time.Now().Unix())
return &stratum, nil
}
// Reconnect reconnects to a stratum server if the connection has been lost.
func (s *Stratum) Reconnect() error {
var conn net.Conn
var err error
if s.cfg.Proxy != "" {
proxy := &socks.Proxy{
Addr: s.cfg.Proxy,
Username: s.cfg.ProxyUser,
Password: s.cfg.ProxyPass,
}
conn, err = proxy.Dial("tcp", s.cfg.Pool)
} else {
conn, err = net.Dial("tcp", s.cfg.Pool)
}
if err != nil {
return err
}
s.Conn = conn
s.Reader = bufio.NewReader(s.Conn)
err = s.Subscribe()
if err != nil {
13 16" ONGUARD Cleated Toe Polyblend Size Polyurethane Men's Height Boots Knee 86101 with Outsole Plain PVC return nil
}
// Should NOT need this.
time.Sleep(5 * time.Second)
// XXX Do I really need to re-auth here?
err = s.Auth()
if err != nil {
return nil
}
16" Toe with Men's 86101 ONGUARD PVC Boots Polyblend Outsole 13 Cleated Polyurethane Plain Height Knee Size
// If we were able to reconnect, restart counter
s.Started = uint32(time.Now().Unix())
return nil
}
// Listen is the listener for the incoming messages from the stratum pool.
func (s *Stratum) Listen() {
log.Debug("Starting Listener")
for {
result, err := s.Reader.ReadString('\n')
if err != nil {
if err == io.EOF {
log.Error("Connection lost! Reconnecting.")
err = s.Reconnect()
if err != nil {
log.Error(err)
log.Error("Reconnect failed.")
os.Exit(1)
return
}
} else {
log.Error(err)
}
continue
}
log.Debug(strings.TrimSuffix(result, "\n"))
resp, err := s.Unmarshal([]byte(result))
if err != nil {
log.Error(err)
continue
}
switch resp.(type) {
case *BasicReply:
s.handleBasicReply(resp)
case StratumMsg:
s.handleStratumMsg(resp)
case NotifyRes:
s.handleNotifyRes(resp)
case *SubscribeReply:
s.handleSubscribeReply(resp)
default:
log.Info("Unhandled message: ", result)
}
}
}
func (s *Stratum) handleBasicReply(resp interface{}) {
s.Lock()
defer s.Unlock()
aResp := resp.(*BasicReply)
if int(aResp.ID.(uint64)) == int(s.authID) {
if aResp.Result {
log.Debug("Logged in")
} else {
log.Error("Auth failure.")
}
}
if sliceContains(s.submitIDs, aResp.ID.(uint64)) {
if aResp.Result {
atomic.AddUint64(&s.ValidShares, 1)
log.Debug("Share accepted")
} else {
atomic.AddUint64(&s.InvalidShares, 1)
log.Error("Share rejected: ", aResp.Error.ErrStr)
}
s.submitIDs = sliceRemove(s.submitIDs, aResp.ID.(uint64))
}
}
func (s *Stratum) handleStratumMsg(resp interface{}) {
nResp := resp.(StratumMsg)
log.Trace(nResp)
// Too much is still handled in unmarshaler. Need to
// move stuff other than unmarshalling here.
switch nResp.Method {
case "client.show_message":
log.Info(nResp.Params)
case "client.reconnect":
log.Debug("Reconnect requested")
wait, err := strconv.Atoi(nResp.Params[2])
if err != nil {
log.Error(err)
return
}
time.Sleep(time.Duration(wait) * time.Second)
pool := nResp.Params[0] + ":" + nResp.Params[1]
s.cfg.Pool = pool
err = s.Reconnect()
if err != nil {
log.Error(err)
// XXX should just die at this point
// but we don't really have access to
// the channel to end everything.
return
}
case "client.get_version":
log.Debug("get_version request received.")
msg := StratumMsg{
Method: nResp.Method,
ID: nResp.ID,
Params: []string{"decred-gominer/" + s.cfg.Version},
}
m, err := json.Marshal(msg)
if err != nil {
log.Error(err)
return
}
_, err = s.Conn.Write(m)
if err != nil {
log.Error(err)
return
}
_, err = s.Conn.Write([]byte("\n"))
if err != nil {
log.Error(err)
return
}
}
}
func (s *Stratum) handleNotifyRes(resp interface{}) {
s.Lock()
defer s.Unlock()
nResp := resp.(NotifyRes)
s.PoolWork.JobID = nResp.JobID
s.PoolWork.CB1 = nResp.GenTX1
heightHex := nResp.GenTX1[186:188] + nResp.GenTX1[184:186]
height, err := strconv.ParseInt(heightHex, 16, 32)
if err != nil {
log.Debugf("failed to parse height %v", err)
height = 0
}
s.PoolWork.Height = height
s.PoolWork.CB2 = nResp.GenTX2
s.PoolWork.Hash = nResp.Hash
s.PoolWork.Nbits = nResp.Nbits
s.PoolWork.Version = nResp.BlockVersion
parsedNtime, err := strconv.ParseInt(nResp.Ntime, 16, 64)
if err != nil {
log.Error(err)
}
s.PoolWork.Ntime = nResp.Ntime
s.PoolWork.NtimeDelta = parsedNtime - time.Now().Unix()
s.PoolWork.Clean = nResp.CleanJobs
s.PoolWork.NewWork = true
log.Trace("notify: ", spew.Sdump(nResp))
}
func (s *Stratum) handleSubscribeReply(resp interface{}) {
nResp := resp.(*SubscribeReply)
s.PoolWork.ExtraNonce1 = nResp.ExtraNonce1
s.PoolWork.ExtraNonce2Length = nResp.ExtraNonce2Length
log.Debug("Subscribe reply received.")
log.Trace(spew.Sdump(resp))
}
// Auth sends a message to the pool to authorize a worker.
func (s *Stratum) Auth() error {
msg := StratumMsg{
Method: "mining.authorize",
ID: s.ID,
Params: []string{s.cfg.User, s.cfg.Pass},
}
// Auth reply has no method so need a way to identify it.
// Ugly, but not much choice.
id, ok := msg.ID.(uint64)
if !ok {
return errJsonType
}
s.authID = id
s.ID++
log.Tracef("%v", msg)
m, err := json.Marshal(msg)
if err != nil {
return err
}
_, err = s.Conn.Write(m)
if err != nil {
return err
}
_, err = s.Conn.Write([]byte("\n"))
if err != nil {
return err
}
return nil
}
// Subscribe sends the subscribe message to get mining info for a worker.
func (s *Stratum) Subscribe() error {
msg := StratumMsg{
Method: "mining.subscribe",
ID: s.ID,
Params: []string{"decred-gominer/" + s.cfg.Version},
}
s.subID = msg.ID.(uint64)
s.ID++
m, err := json.Marshal(msg)
if err != nil {
return err
}
log.Tracef("%v", string(m))
_, err = s.Conn.Write(m)
if err != nil {
return err
}
_, err = s.Conn.Write([]byte("\n"))
if err != nil {
return err
}
return nil
}
// Unmarshal provides a json unmarshaler for the commands.
// I'm sure a lot of this can be generalized but the json we deal with
// is pretty yucky.
func (s *Stratum) Unmarshal(blob []Size Men's 16" Polyblend Knee Plain Boots Toe Polyurethane with Outsole ONGUARD PVC 86101 Height 13 Cleated byte) (interface{}, error) {
s.Lock()
defer s.Unlock()
var (
objmap map[string]json.RawMessage
method string
id uint64
)
err := json.Unmarshal(blob, &objmap)
if err != nil {
return nil, err
}
// decode command
// Not everyone has a method.
err = json.Unmarshal(objmap["method"], &method)
if err != nil {
method = ""
}
err = json.Unmarshal(objmap["id"], &id)
if err != nil {
return nil, err
}
log.Trace("Received: method: ", method, " id: ", id)
if id == s.authID {
var (
objmap map[string]json.RawMessage
id uint64
result bool
errorHolder []interface{}
)
err := json.Unmarshal(blob, &objmap)
if err != nil {
return nil, err
}
resp := &BasicReply{}
err = json.Unmarshal(objmap["id"], &id)
if err != nil {
return nil, err
}
resp.ID = id
err = json.Unmarshal(objmap["result"], &result)
if err != nil {
return nil, err
}
err = json.Unmarshal(objmap["error"], &errorHolder)
if err != nil {
return nil, err
}
resp.Result = result
if errorHolder != nil {
errN, ok := errorHolder[0].(float64)
if !ok {
return nil, errJsonType
}
errS, ok := errorHolder[1].(string)
if !ok {
return nil, errJsonType
}
resp.Error.ErrNum = uint64(errN)
resp.Error.ErrStr = errS
}
return resp, nil
}
if id == s.subID {
var resi []interface{}
err := json.Unmarshal(objmap["result"], &resi)
if err != nil {
return nil, err
}
log.Trace(resi)
resp := &SubscribeReply{}
var objmap2 map[string]json.RawMessage
err = json.Unmarshal(blob, &objmap2)
if err != nil {
return nil, err
}
var resJS []json.RawMessage
err = json.Unmarshal(objmap["result"], &resJS)
if err != nil {
return nil, err
}
if len(resJS) == 0 {
return nil, errJsonType
}
var msgPeak []interface{}
err = json.Unmarshal(resJS[0], &msgPeak)
if err != nil {
return nil, err
}
// The pools do not all agree on what this message looks like
// so we need to actually look at it before unmarshalling for
// real so we can use the right form. Yuck.
if msgPeak[0] == "mining.notify" {
var innerMsg []string
err = json.Unmarshal(resJS[0], &innerMsg)
if err != nil {
return nil, err
}
resp.SubscribeID = innerMsg[1]
} else {
var innerMsg [][]string
err = json.Unmarshal(resJS[0], &innerMsg)
if err != nil {
return nil, err
}
for i := 0; i < len(innerMsg); i++ {
if innerMsg[i][0] == "mining.notify" {
resp.SubscribeID = innerMsg[i][1]
}
if innerMsg[i][0] == "mining.set_difficulty" {
// Not all pools correctly put something
// in here so we will ignore it (we
// already have the default value of 1
// anyway and pool can send a new one.
// dcr.coinmine.pl puts something that
// is not a difficulty here which is why
// we ignore.
}
}
Knee 16" 13 86101 Boots Height Cleated Polyblend ONGUARD Toe Plain with Men's Polyurethane Outsole PVC Size }
resp.ExtraNonce1 = resi[1].(string)
resp.ExtraNonce2Length = resi[2].(float64)
return resp, nil
}
if sliceContains(s.submitIDs, id) {
var (
objmap map[string]json.RawMessage
Polyurethane Cleated Polyblend with Size Boots ONGUARD Men's Outsole PVC 86101 16" Plain Knee 13 Height Toe id uint64
result bool
errorHolder []interface{}
)
err := json.Unmarshal(blob, &objmap)
if err != nil {
return nil, err
}
resp := &BasicReply{}
err = json.Unmarshal(objmap["id"], &id)
if err != nil {
return nil, err
}
resp.ID = id
err = json.Unmarshal(objmap["result"], &result)
if err != nil {
return nil, err
}
err = json.Unmarshal(objmap["error"], &errorHolder)
if err != nil {
return nil, err
}
resp.Result = result
if errorHolder != nil {
errN, ok := errorHolder[0].(float64)
if !ok {
return nil, errJsonType
}
errS, ok := errorHolder[1].(string)
if !ok {
return nil, errJsonType
}
resp.Error.ErrNum = uint64(errN)
resp.Error.ErrStr = errS
}
return resp, nil
}
switch method {
case "mining.notify":
log.Trace("Unmarshal mining.notify")
var resi []interface{}
err := json.Unmarshal(objmap["params"], &resi)
if err != nil {
return nil, err
}
var nres = NotifyRes{}
jobID, ok 13 Polyblend Men's Knee 86101 Outsole Height Plain with PVC Polyurethane 16" Cleated Toe ONGUARD Boots Size := resi[0].(string)
if !ok {
return nil, errJsonType
}
nres.JobID = jobID
hash, ok := resi[1].(string)
if !ok {
return nil, errJsonType
}
nres.Hash = hash
genTX1, ok := resi[2].(string)
if !ok {
return nil, errJsonType
}
nres.GenTX1 = genTX1
genTX2, ok := resi[3].(string)
if !ok {
return nil, errJsonType
}
nres.GenTX2 = genTX2
//ccminer code also confirms this
//nres.MerkleBranches = resi[4].([]string)
blockVersion, ok := resi[5].(string)
if !ok {
return nil, errJsonType
}
nres.BlockVersion = blockVersion
nbits, ok := resi[6].(string)
if !ok {
return nil, errJsonType
}
nres.Nbits = nbits
ntime, ok := resi[7].(string)
if !ok {
return nil, errJsonType
}
nres.Ntime = ntime
cleanJobs, ok := resi[8].(bool)
if !ok {
return nil, errJsonType
}
nres.CleanJobs = cleanJobs
return nres, nil
case "mining.set_difficulty":
log.Trace("Received new difficulty.")
var resi []interface{}
err := json.Unmarshal(objmap["params"], &resi)
if err != nil {
return nil, err
}
difficulty, ok := resi[0].(float64)
if !ok {
return nil, errJsonType
}
s.Target, err = util.DiffToTarget(difficulty, chainParams.PowLimit)
if err != nil {
return nil, err
}
s.Diff = difficulty
var nres = StratumMsg{}
nres.Method = method
diffStr := strconv.FormatFloat(difficulty, 'E', -1, 32)
var params []string
params = append(params, diffStr)
nres.Params = params
log.Infof("Stratum difficulty set to %v", difficulty)
return nres, nil
case "client.show_message":
var resi []interface{}
err := json.Unmarshal(objmap["result"], &resi)
if err != nil {
return nil, err
}
msg, ok := resi[0].(string)
if !ok {
return nil, errJsonType
}
var nres = StratumMsg{}
nres.Method = method
var params []string
params = append(params, msg)
nres.Params = params
return nres, nil
case "client.get_version":
var nres = StratumMsg{}
var id uint64
err = json.Unmarshal(objmap["id"], &id)
if err != nil {
return nil, err
}
nres.Method = method
nres.ID = id
return nres, nil
case "client.reconnect":
var nres = StratumMsg{}
var id uint64
err = json.Unmarshal(objmap["id"], &id)
if err != nil {
return nil, err
}
nres.Method = method
Men's Height 13 Outsole Cleated Plain Toe Polyblend Knee ONGUARD Polyurethane 16" Size 86101 Boots PVC with nres.ID = id
var resi []interface{}
err := json.Unmarshal(objmap["params"], &resi)
if err != nil {
return nil, err
}
log.Trace(resi)
if len(resi) < 3 {
return nil, errJsonType
}
hostname, ok := resi[0].(string)
if !ok {
return nil, errJsonType
}
p, ok := resi[1].(float64)
Height 13 Men's 86101 Plain Size with Knee Boots PVC Polyblend Outsole Toe Polyurethane Cleated ONGUARD 16" if !ok {
return nil, errJsonType
}
port := strconv.Itoa(int(p))
w, ok := resi[2].(float64)
if !ok {
return nil, errJsonType
}
wait := strconv.Itoa(int(w))
nres.Params = []string{hostname, port, wait}
return nres, nil
default:
resp := &StratumRsp{}
err := json.Unmarshal(blob, &resp)
if err != nil {
return nil, err
}
return resp, nil
}
}
// PrepWork converts the stratum notify to getwork style data for mining.
func (s *Stratum) PrepWork() error {
// Build final extranonce, which is basically the pool user and worker
// ID.
en1, err := hex.DecodeString(s.PoolWork.ExtraNonce1)
if err != nil {
log.Error("Error decoding ExtraNonce1.")
return err
}
// Work out padding.
tmp := []string{"%0", strconv.Itoa(int(s.PoolWork.ExtraNonce2Length) * 2), "x"}
fmtString := strings.Join(tmp, "")
en2, err := hex.DecodeString(fmt.Sprintf(fmtString, s.PoolWork.ExtraNonce2))
if err != nil {
log.Error("Error decoding ExtraNonce2.")
return err
}
extraNonce := append(en1[:], en2[:]...)
// Put coinbase transaction together.
cb1, err := hex.DecodeString(s.PoolWork.CB1)
if err != nil {
log.Error("Error decoding Coinbase pt 1.")
return err
}
cb2, err := hex.DecodeString(s.PoolWork.CB2)
if err != nil {
log.Errorf("Error decoding Coinbase pt 2.")
return err
}
// Generate current ntime.
ntime := time.Now().Unix() + s.PoolWork.NtimeDelta
log.Tracef("ntime: %x", ntime)
// Serialize header.
bh := wire.BlockHeader{}
v, err := util.ReverseToInt(s.PoolWork.Version)
if err != nil {
return err
}
bh.Version = v
nbits, err := hex.DecodeString(s.PoolWork.Nbits)
if err != nil {
log.Error("Error decoding nbits")
return err
}
b, _ := binary.Uvarint(nbits)
bh.Bits = uint32(b)
t := time.Now().Unix() + s.PoolWork.NtimeDelta
bh.Timestamp = time.Unix(t, 0)
bh.Nonce = 0
// Serialized version.
blockHeader, err := bh.Bytes()
if err != nil {
return err
}
data Polyblend Cleated ONGUARD Knee Plain Polyurethane 86101 Size Outsole 13 Height with PVC Men's 16" Toe Boots := blockHeader
copy(data[31:139], cb1[0:108])
var workdata [180]byte
workPosition := 0
version := new(bytes.Buffer)
err = binary.Write(version, binary.LittleEndian, v)
if err != nil {
return err
}
copy(workdata[workPosition:], version.Bytes())
prevHash := util.RevHash(s.PoolWork.Hash)
p, err := hex.DecodeString(prevHash)
if err != nil {
log.Error("Error encoding previous hash.")
return err
}
workPosition += 4
copy(workdata[workPosition:], p)
workPosition += 32
copy(workdata[workPosition:], cb1[0:Boots Outsole Men's 13 Polyblend ONGUARD 16" with Polyurethane Plain Size Cleated PVC Toe 86101 Height Knee 108])
workPosition += 108
copy(workdata[workPosition:], extraNonce)
workPosition = 176
copy(workdata[workPosition:], cb2)
var randomBytes = make([]byte, 4)
_, err = rand.Read(randomBytes)
if err != nil {
log.Errorf("Unable to generate random bytes")
return err
}
var workData [192]byte
copy(workData[:], workdata[:])
givenTs := binary.LittleEndian.Uint32(
workData[128+4*work.TimestampWord : 132+4*work.TimestampWord])
atomic.StoreUint32(&s.latestJobTime, givenTs)
if s.Target == nil {
log.Errorf("No target set! Reconnecting to pool.")
err = s.Reconnect()
if err != nil {
log.Error(err)
// XXX should just die at this point
// but we don't really have access to
// the channel to end everything.
return err
}
return Outsole ONGUARD Knee Boots Polyurethane with 16" Men's 86101 Polyblend Cleated PVC Toe Plain Size 13 Height nil
}
w := work.NewWork(workData, s.Target, givenTs, uint32(time.Now().Unix()), false)
log.Tracef("Stratum prepated work data %v, target %032x",
hex.EncodeToString(w.Data[:]), w.Target.Bytes())
s.PoolWorkMule Dark Women's Navy Easy Spirit Eliana Suede Grey RqwZSwa1xp.Work = w
return nil
}
// PrepSubmit formats a mining.sumbit message from the solved work.
func (s *Stratum) PrepSubmit(data []byte) (Submit, error) {
log.Debugf("Stratum got valid work to submit %x", data)
log.Debugf("Stratum got valid work hash %v",
chainhash.HashH(data[0:180]))
data2 := make([]byte, 180)
copy(data2, data[0:180])
sub := Submit{}
sub.Method = "mining.submit"
// Format data to send off.
hexData := hex.EncodeToString(data)
decodedData, err := hex.DecodeString(hexData)
if err != nil {
log.Error("Error decoding data")
return sub, err
}
var submittedHeader wire.BlockHeader
bhBuf := bytes.NewReader(decodedData[0:wire.MaxBlockHeaderPayload])
err = submittedHeader.Deserialize(bhBuf)
if err != nil {
log.Error("Error generating header")
return sub, err
}
latestWorkTs := atomic.LoadUint32(&s.latestJobTime)
if uint32(submittedHeader.Timestamp.Unix()) != latestWorkTs {
Toe Height Outsole ONGUARD Men's Polyurethane 13 Knee with Cleated Boots 16" Polyblend PVC Plain 86101 Size return sub, ErrStratumStaleWork
}
s.ID++
sub.ID = s.ID
s.submitIDs = append(s.submitIDs, s.ID)
// The timestamp string should be:
//
// timestampStr := fmt.Sprintf("%08x",
// uint32(submittedHeader.Timestamp.Unix()))
//
// but the "stratum" protocol appears to only use this value
// to check if the miner is in sync with the latest announcement
// of work from the pool. If this value is anything other than
// the timestamp of the latest pool work timestamp, work gets
// rejected from the current implementation.
timestampStr := fmt.Sprintf("%08x", latestWorkTs)
nonceStr := fmt.Sprintf("%08x", submittedHeader.Nonce)
xnonceStr := hex.EncodeToString(data[144:156])
sub.Params = []string{s.cfg.User, s.PoolWork.JobID, xnonceStr, timestampStr,
nonceStr}
return sub, nil
}