-
Notifications
You must be signed in to change notification settings - Fork 0
/
stratum_server.go
125 lines (108 loc) · 3.62 KB
/
stratum_server.go
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
package spectrestratum
import (
"context"
"net/http"
_ "net/http/pprof"
"os"
"time"
"github.com/mattn/go-colorable"
"github.com/spectre-project/spectre-stratum-bridge/src/gostratum"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
const version = "v0.3.15"
const minBlockWaitTime = 3 * time.Second
type BridgeConfig struct {
StratumPort string `yaml:"stratum_port"`
RPCServer string `yaml:"spectred_address"`
PromPort string `yaml:"prom_port"`
PrintStats bool `yaml:"print_stats"`
UseLogFile bool `yaml:"log_to_file"`
HealthCheckPort string `yaml:"health_check_port"`
BlockWaitTime time.Duration `yaml:"block_wait_time"`
MinShareDiff uint `yaml:"min_share_diff"`
VarDiff bool `yaml:"var_diff"`
SharesPerMin uint `yaml:"shares_per_min"`
VarDiffStats bool `yaml:"var_diff_stats"`
ExtranonceSize uint `yaml:"extranonce_size"`
}
func configureZap(cfg BridgeConfig) (*zap.SugaredLogger, func()) {
pe := zap.NewProductionEncoderConfig()
pe.EncodeTime = zapcore.RFC3339TimeEncoder
fileEncoder := zapcore.NewJSONEncoder(pe)
consoleEncoder := zapcore.NewConsoleEncoder(pe)
if !cfg.UseLogFile {
return zap.New(zapcore.NewCore(consoleEncoder,
zapcore.AddSync(colorable.NewColorableStdout()), zap.InfoLevel)).Sugar(), func() {}
}
// log file fun
logFile, err := os.OpenFile("bridge.log", os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666)
if err != nil {
panic(err)
}
core := zapcore.NewTee(
zapcore.NewCore(fileEncoder, zapcore.AddSync(logFile), zap.InfoLevel),
zapcore.NewCore(consoleEncoder, zapcore.AddSync(colorable.NewColorableStdout()), zap.InfoLevel),
)
return zap.New(core).Sugar(), func() { logFile.Close() }
}
func ListenAndServe(cfg BridgeConfig) error {
logger, logCleanup := configureZap(cfg)
defer logCleanup()
if cfg.PromPort != "" {
StartPromServer(logger, cfg.PromPort)
}
blockWaitTime := cfg.BlockWaitTime
if blockWaitTime == 0 {
blockWaitTime = minBlockWaitTime
}
sprApi, err := NewSpectreAPI(cfg.RPCServer, blockWaitTime, logger)
if err != nil {
return err
}
if cfg.HealthCheckPort != "" {
logger.Info("enabling health check on port " + cfg.HealthCheckPort)
http.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
go http.ListenAndServe(cfg.HealthCheckPort, nil)
}
shareHandler := newShareHandler(sprApi.spectred)
minDiff := cfg.MinShareDiff
if minDiff == 0 {
minDiff = 4
}
extranonceSize := cfg.ExtranonceSize
if extranonceSize > 3 {
extranonceSize = 3
}
clientHandler := newClientListener(logger, shareHandler, float64(minDiff), int8(extranonceSize))
handlers := gostratum.DefaultHandlers()
// override the submit handler with an actual useful handler
handlers[string(gostratum.StratumMethodSubmit)] =
func(ctx *gostratum.StratumContext, event gostratum.JsonRpcEvent) error {
if err := shareHandler.HandleSubmit(ctx, event); err != nil {
ctx.Logger.Sugar().Error(err) // sink error
}
return nil
}
stratumConfig := gostratum.StratumListenerConfig{
Port: cfg.StratumPort,
HandlerMap: handlers,
StateGenerator: MiningStateGenerator,
ClientListener: clientHandler,
Logger: logger.Desugar(),
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sprApi.Start(ctx, func() {
clientHandler.NewBlockAvailable(sprApi)
})
if cfg.VarDiff {
go shareHandler.startVardiffThread(cfg.SharesPerMin, cfg.VarDiffStats)
}
if cfg.PrintStats {
go shareHandler.startStatsThread()
}
return gostratum.NewListener(stratumConfig).Listen(context.Background())
}