-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathjob_types.go
More file actions
196 lines (182 loc) · 6.25 KB
/
Copy pathjob_types.go
File metadata and controls
196 lines (182 loc) · 6.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package main
import (
"context"
"errors"
"math/big"
"sync"
"sync/atomic"
"time"
"github.com/remeh/sizedwaitgroup"
)
// GetBlockTemplateResult mirrors BIP22/23 getblocktemplate fields.
// See docs/protocols/bip-0022.mediawiki and docs/protocols/bip-0023.mediawiki.
type GetBlockTemplateResult struct {
Bits string `json:"bits"`
CurTime int64 `json:"curtime"`
Height int64 `json:"height"`
Mintime int64 `json:"mintime"`
Target string `json:"target"`
Version int32 `json:"version"`
Previous string `json:"previousblockhash"`
CoinbaseValue int64 `json:"coinbasevalue"`
DefaultWitnessCommitment string `json:"default_witness_commitment"`
LongPollID string `json:"longpollid"`
Transactions []GBTTransaction `json:"transactions"`
VbAvailable map[string]int `json:"vbavailable"`
VbRequired int `json:"vbrequired"`
Mutable []string `json:"mutable"`
Rules []string `json:"rules"`
CoinbaseAux struct {
Flags string `json:"flags"`
} `json:"coinbaseaux"`
}
type GBTTransaction struct {
Data string `json:"data"`
Txid string `json:"txid"`
Hash string `json:"hash"`
}
type Job struct {
JobID string
Generation uint64
Template GetBlockTemplateResult
Target *big.Int
targetBE [32]byte
CreatedAt time.Time
Clean bool
Extranonce2Size int
CoinbaseValue int64
WitnessCommitment string
CoinbaseMsg string
MerkleBranches []string
merkleBranchesBytes [][32]byte
Transactions []GBTTransaction
TransactionIDs [][]byte
PayoutScript []byte
PayoutAddress string
PoolFeePercent float64
PayoutPolicyCaptured bool
DonationScript []byte
OperatorDonationPercent float64
VersionMask uint32
PrevHash string
prevHashBytes [32]byte
bitsBytes [4]byte
coinbaseFlagsBytes []byte
witnessCommitScript []byte
ScriptTime int64
TemplateExtraNonce2Size int
CoinbaseScriptSigMaxBytes int
}
const (
jobSubscriberBuffer = 4
coinbaseExtranonce1Size = 4
)
const (
jobRetryDelayMin = 5 * time.Second
jobRetryDelayMax = 20 * time.Second
)
var errStaleTemplate = errors.New("stale template")
type JobFeedPayloadStatus struct {
LastRawBlockAt time.Time
LastRawBlockBytes int
BlockTip ZMQBlockTip
RecentBlockTimes []time.Time // Last 4 block times
BlockTimerActive bool // Whether block timer should count down (only after first new block)
}
type ZMQBlockTip struct {
Hash string
Height int64
Time time.Time
Bits string
Difficulty float64
}
const jobFeedErrorHistorySize = 3
type JobManager struct {
rpc *RPCClient
cfg Config
zmqHashBlockAddr string
zmqRawBlockAddr string
metrics *PoolMetrics
mu sync.RWMutex
curJob *Job
longPollID string // Latest accepted opaque cursor; independent of published job identity.
payoutScript []byte
donationScript []byte
extraID uint32
jobIDCounter uint64
jobGeneration uint64
subs map[chan *Job]struct{}
subsMu sync.Mutex
zmqHashblockHealthy atomic.Bool
zmqRawblockHealthy atomic.Bool
zmqDisconnects uint64
zmqReconnects uint64
lastErrMu sync.RWMutex
lastErr error
lastErrAt time.Time
lastJobSuccess time.Time
jobFeedErrHistory []string
// Refresh/apply coordination to prevent concurrent refreshes and concurrent
// template application from longpoll/ZMQ.
refreshMu sync.Mutex
lastRefreshAttempt time.Time
refreshRPCTimeout time.Duration
applyMu sync.Mutex
// historyMu serializes the best-effort block-history worker. At most one
// RPC walk is active and one newest request is pending, so template churn
// cannot create an unbounded goroutine/RPC backlog.
historyMu sync.Mutex
historyRunning bool
historyPending blockHistoryRefreshRequest
historyPendingSet bool
historyLatest uint64
historyCtx context.Context
historyRPCTimeout time.Duration
// blockTipSequence advances when an authoritative raw-block notification
// replaces the payload tip. It is guarded by zmqPayloadMu.
blockTipSequence uint64
zmqPayload JobFeedPayloadStatus
zmqPayloadMu sync.RWMutex
// nodeSync* tracks whether the node is in a usable state for mining.
// When the node reports IBD/syncing, we treat Stratum as degraded to avoid
// miners wasting power on stale work.
nodeSyncMu sync.RWMutex
nodeIBD bool
nodeBlocks int64
nodeHeaders int64
nodeSyncFetched time.Time
// Async notification queue
notifyQueue chan *Job
notifyWg sizedwaitgroup.SizedWaitGroup
// Callback for new block notifications
onNewBlock func()
// Retry backoff state for job refresh loops
retryDelay time.Duration
retryMu sync.Mutex
}
func NewJobManager(rpc *RPCClient, cfg Config, metrics *PoolMetrics, payoutScript []byte, donationScript []byte) *JobManager {
return &JobManager{
rpc: rpc,
cfg: cfg,
zmqHashBlockAddr: cfg.ZMQHashBlockAddr,
zmqRawBlockAddr: cfg.ZMQRawBlockAddr,
metrics: metrics,
payoutScript: append([]byte(nil), payoutScript...),
donationScript: append([]byte(nil), donationScript...),
subs: make(map[chan *Job]struct{}),
notifyQueue: make(chan *Job, 100), // Buffered queue for async notifications
refreshRPCTimeout: jobTemplateRefreshTimeout,
historyRPCTimeout: jobBlockHistoryRefreshTimeout,
}
}
type JobFeedStatus struct {
Ready bool
LastSuccess time.Time
LastError error
LastErrorAt time.Time
ErrorHistory []string
ZMQHealthy bool
ZMQDisconnects uint64
ZMQReconnects uint64
Payload JobFeedPayloadStatus
}