Pool mining support

- pool mining support added (not for stratum pools)
- fixed an issue that caused a crash when miners connect at a certain point
This commit is contained in:
8lecramm 2022-08-19 22:04:41 +02:00 committed by GitHub
parent 52b82854cb
commit 80c9995ea4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 111 additions and 39 deletions

View File

@ -8,13 +8,15 @@ Long To-Do list, but this is a working release.
- muliple wallets are supported - muliple wallets are supported
- notification of incoming and lost connections / submitted results / stats - notification of incoming and lost connections / submitted results / stats
- user-defined logging interval - user-defined logging interval
- pool mining support (not stratum)
**Usage** **Usage**
```derohe-proxy [--listen-address=<127.0.0.1:11111>] [--log-interval=<60>] [--minimal] [--nonce] --daemon-address=<1.2.3.4:10100>``` ```derohe-proxy [--listen-address=<127.0.0.1:11111>] [--log-interval=<60>] [--minimal] [--nonce] [--pool] --daemon-address=<1.2.3.4:10100>```
```--listen-address (optional): bind to address:port for incoming miner connections. By default, proxy listens on 0.0.0.0:10200 ```--listen-address (optional): bind to address:port for incoming miner connections. By default, proxy listens on 0.0.0.0:10200
--daemon-address: address:port of daemon --daemon-address: address:port of daemon
--log-interval (optional): logging every X seconds, where X >= 60. Default is 60 seconds --log-interval (optional): logging every X seconds, where X >= 60. Default is 60 seconds
--minimal (optional): forward only 2 jobs per block (1 for first 9 miniblocks, 1 for final miniblock) --minimal (optional): forward only 2 jobs per block (1 for first 9 miniblocks, 1 for final miniblock)
--nonce (optional): enable random nonces, disabled by default``` --nonce (optional): enable random nonces, disabled by default```
--pool (optional): enable pool mining, disable keyhash replacement

36
config/config.go Normal file
View File

@ -0,0 +1,36 @@
package config
var Command_line string = `derohe-proxy
Proxy to combine all miners and to reduce network load
Usage:
derohe-proxy [--listen-address=<127.0.0.1:10100>] [--log-interval=<60>] [--minimal] [--nonce] [--pool] --daemon-address=<1.2.3.4:10100>
Options:
--listen-address=<127.0.0.1:10100> bind to specific address:port, default is 0.0.0.0:10200
--daemon-address=<1.2.3.4:10100> connect to this daemon
--log-interval=<60> set logging interval in seconds (range 60 - 3600), default is 60 seconds
--minimal forward only 2 jobs per block (1 for miniblocks and 1 for final miniblock), by default all jobs are forwarded
--nonce enable nonce editing, default is off
--pool use this option for pool mining; this option avoids changing the keyhash
Example Mainnet: ./derohe-proxy --daemon-address=minernode1.dero.io:10100
`
// program arguments
var Arguments = map[string]interface{}{}
var Listen_addr string = "0.0.0.0:10200"
var Daemon_address string = "minernode1.dero.io:10100"
// logging interval in seconds
var Log_intervall int = 60
// send only 2 jobs per block
var Minimal bool = false
// edit nonce
var Nonce bool = false
// pool mining
var Pool_mode bool = false

View File

@ -1,10 +1,12 @@
package main package main
import ( import (
"derohe-proxy/config"
"derohe-proxy/proxy" "derohe-proxy/proxy"
"fmt" "fmt"
"net" "net"
"strconv" "strconv"
"sync"
"time" "time"
"github.com/docopt/docopt-go" "github.com/docopt/docopt-go"
@ -12,68 +14,75 @@ import (
func main() { func main() {
var err error var err error
var rwmutex sync.RWMutex
Arguments, err = docopt.Parse(command_line, nil, true, "pre-alpha", false) config.Arguments, err = docopt.Parse(config.Command_line, nil, true, "pre-alpha", false)
if err != nil { if err != nil {
return return
} }
if Arguments["--listen-address"] != nil { if config.Arguments["--listen-address"] != nil {
addr, err := net.ResolveTCPAddr("tcp", Arguments["--listen-address"].(string)) addr, err := net.ResolveTCPAddr("tcp", config.Arguments["--listen-address"].(string))
if err != nil { if err != nil {
return return
} else { } else {
if addr.Port == 0 { if addr.Port == 0 {
return return
} else { } else {
listen_addr = addr.String() config.Listen_addr = addr.String()
} }
} }
} }
if Arguments["--daemon-address"] == nil { if config.Arguments["--daemon-address"] == nil {
return return
} else { } else {
daemon_address = Arguments["--daemon-address"].(string) config.Daemon_address = config.Arguments["--daemon-address"].(string)
} }
if Arguments["--log-interval"] != nil { if config.Arguments["--log-interval"] != nil {
interval, err := strconv.ParseInt(Arguments["--log-interval"].(string), 10, 32) interval, err := strconv.ParseInt(config.Arguments["--log-interval"].(string), 10, 32)
if err != nil { if err != nil {
return return
} else { } else {
if interval < 60 || interval > 3600 { if interval < 60 || interval > 3600 {
log_intervall = 60 config.Log_intervall = 60
} else { } else {
log_intervall = int(interval) config.Log_intervall = int(interval)
} }
} }
} }
if Arguments["--minimal"].(bool) { if config.Arguments["--minimal"].(bool) {
minimal = true config.Minimal = true
fmt.Printf("%v Forward only 2 jobs per block\n", time.Now().Format(time.Stamp)) fmt.Printf("%v Forward only 2 jobs per block\n", time.Now().Format(time.Stamp))
} }
if Arguments["--nonce"].(bool) { if config.Arguments["--nonce"].(bool) {
nonce = true config.Nonce = true
fmt.Printf("%v Nonce editing is enabled\n", time.Now().Format(time.Stamp)) fmt.Printf("%v Nonce editing is enabled\n", time.Now().Format(time.Stamp))
} }
fmt.Printf("%v Logging every %d seconds\n", time.Now().Format(time.Stamp), log_intervall) if config.Arguments["--pool"].(bool) {
config.Pool_mode = true
config.Minimal = false
fmt.Printf("%v Pool mode is enabled\n", time.Now().Format(time.Stamp))
}
go proxy.Start_server(listen_addr) fmt.Printf("%v Logging every %d seconds\n", time.Now().Format(time.Stamp), config.Log_intervall)
go proxy.Start_server()
// Wait for first miner connection to grab wallet address // Wait for first miner connection to grab wallet address
for proxy.CountMiners() < 1 { for proxy.CountMiners() < 1 {
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
} }
go proxy.Start_client(daemon_address, proxy.Address, minimal, nonce) go proxy.Start_client(proxy.Address)
go proxy.SendUpdateToDaemon() go proxy.SendUpdateToDaemon()
for { for {
time.Sleep(time.Second * time.Duration(log_intervall)) time.Sleep(time.Second * time.Duration(config.Log_intervall))
hash_rate_string := "" hash_rate_string := ""
@ -90,11 +99,17 @@ func main() {
hash_rate_string = fmt.Sprintf("%d H/s", int(proxy.Hashrate)) hash_rate_string = fmt.Sprintf("%d H/s", int(proxy.Hashrate))
} }
fmt.Printf("%v %d miners connected, IB:%d MB:%d MBR:%d MBO:%d - MINING @ %s\n", time.Now().Format(time.Stamp), proxy.CountMiners(), proxy.Blocks, proxy.Minis, proxy.Rejected, proxy.Orphans, hash_rate_string) if !config.Pool_mode {
fmt.Printf("%v %d miners connected, IB:%d MB:%d MBR:%d MBO:%d - MINING @ %s\n", time.Now().Format(time.Stamp), proxy.CountMiners(), proxy.Blocks, proxy.Minis, proxy.Rejected, proxy.Orphans, hash_rate_string)
} else {
fmt.Printf("%v %d miners connected, Pool stats: IB:%d MB:%d MBR:%d MBO:%d - MINING @ %s\n", time.Now().Format(time.Stamp), proxy.CountMiners(), proxy.Blocks, proxy.Minis, proxy.Rejected, proxy.Orphans, hash_rate_string)
}
rwmutex.RLock()
for i := range proxy.Wallet_count { for i := range proxy.Wallet_count {
if proxy.Wallet_count[i] > 1 { if proxy.Wallet_count[i] > 1 {
fmt.Printf("%v Wallet %v, %d miners\n", time.Now().Format(time.Stamp), i, proxy.Wallet_count[i]) fmt.Printf("%v Wallet %v, %d miners\n", time.Now().Format(time.Stamp), i, proxy.Wallet_count[i])
} }
} }
rwmutex.RUnlock()
} }
} }

View File

@ -8,6 +8,8 @@ import (
"net/url" "net/url"
"time" "time"
"derohe-proxy/config"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
@ -45,7 +47,7 @@ var ModdedNode bool = false
var Hashrate float64 var Hashrate float64
// proxy-client // proxy-client
func Start_client(v string, w string, min_jobs bool, nonce bool) { func Start_client(w string) {
var err error var err error
var last_diff uint64 var last_diff uint64
var last_height uint64 var last_height uint64
@ -54,14 +56,18 @@ func Start_client(v string, w string, min_jobs bool, nonce bool) {
for { for {
u := url.URL{Scheme: "wss", Host: v, Path: "/ws/" + w} u := url.URL{Scheme: "wss", Host: config.Daemon_address, Path: "/ws/" + w}
dialer := websocket.DefaultDialer dialer := websocket.DefaultDialer
dialer.TLSClientConfig = &tls.Config{ dialer.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
} }
fmt.Println(time.Now().Format(time.Stamp), "Connected to node", v) if !config.Pool_mode {
fmt.Printf("%v Connected to node %v\n", time.Now().Format(time.Stamp), config.Daemon_address)
} else {
fmt.Printf("%v Connected to node %v using wallet %v\n", time.Now().Format(time.Stamp), config.Daemon_address, w)
}
connection, _, err = websocket.DefaultDialer.Dial(u.String(), nil) connection, _, err = websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil { if err != nil {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
@ -92,22 +98,22 @@ func Start_client(v string, w string, min_jobs bool, nonce bool) {
if ModdedNode != params.Hansen33Mod { if ModdedNode != params.Hansen33Mod {
if params.Hansen33Mod { if params.Hansen33Mod {
fmt.Print("Hansen33 Mod Mining Node Detected - Happy Mining\n") fmt.Printf("%v Hansen33 Mod Mining Node Detected - Happy Mining\n", time.Now().Format(time.Stamp))
} }
} }
ModdedNode = params.Hansen33Mod ModdedNode = params.Hansen33Mod
if !ModdedNode { if !ModdedNode {
fmt.Print("Official Mining Node Detected - Happy Mining\n") fmt.Printf("%v Official Mining Node Detected - Happy Mining\n", time.Now().Format(time.Stamp))
} }
if min_jobs { if config.Minimal {
if params.Height != last_height || params.Difficultyuint64 != last_diff { if params.Height != last_height || params.Difficultyuint64 != last_diff {
last_height = params.Height last_height = params.Height
last_diff = params.Difficultyuint64 last_diff = params.Difficultyuint64
go SendTemplateToNodes(recv_data, nonce) go SendTemplateToNodes(recv_data)
} }
} else { } else {
go SendTemplateToNodes(recv_data, nonce) go SendTemplateToNodes(recv_data)
} }
} }
} }

View File

@ -15,6 +15,8 @@ import (
"sync" "sync"
"time" "time"
"derohe-proxy/config"
"github.com/deroproject/derohe/globals" "github.com/deroproject/derohe/globals"
"github.com/deroproject/derohe/rpc" "github.com/deroproject/derohe/rpc"
"github.com/deroproject/graviton" "github.com/deroproject/graviton"
@ -57,10 +59,11 @@ var client_list_mutex sync.Mutex
var client_list = map[*websocket.Conn]*user_session{} var client_list = map[*websocket.Conn]*user_session{}
var miners_count int var miners_count int
var shares uint64
var Wallet_count map[string]uint var Wallet_count map[string]uint
var Address string var Address string
func Start_server(listen string) { func Start_server() {
var err error var err error
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
@ -74,7 +77,7 @@ func Start_server(listen string) {
server = nbhttp.NewServer(nbhttp.Config{ server = nbhttp.NewServer(nbhttp.Config{
Name: "GETWORK", Name: "GETWORK",
Network: "tcp", Network: "tcp",
AddrsTLS: []string{listen}, AddrsTLS: []string{config.Listen_addr},
TLSConfig: tlsConfig, TLSConfig: tlsConfig,
Handler: mux, Handler: mux,
MaxLoad: 10 * 1024, MaxLoad: 10 * 1024,
@ -110,7 +113,7 @@ func CountMiners() int {
} }
// forward all incoming templates from daemon to all miners // forward all incoming templates from daemon to all miners
func SendTemplateToNodes(data []byte, nonce bool) { func SendTemplateToNodes(data []byte) {
client_list_mutex.Lock() client_list_mutex.Lock()
defer client_list_mutex.Unlock() defer client_list_mutex.Unlock()
@ -121,12 +124,14 @@ func SendTemplateToNodes(data []byte, nonce bool) {
break break
} }
miner_address := rv.address_sum if !config.Pool_mode {
miner_address := rv.address_sum
if result := edit_blob(data, miner_address, nonce); result != nil { if result := edit_blob(data, miner_address, config.Nonce); result != nil {
data = result data = result
} else { } else {
fmt.Println(time.Now().Format(time.Stamp), "Failed to change nonce / miner keyhash") fmt.Println(time.Now().Format(time.Stamp), "Failed to change nonce / miner keyhash")
}
} }
go func(k *websocket.Conn, v *user_session) { go func(k *websocket.Conn, v *user_session) {
@ -137,7 +142,6 @@ func SendTemplateToNodes(data []byte, nonce bool) {
}(rk, rv) }(rk, rv)
} }
} }
// handling for incoming miner connections // handling for incoming miner connections
@ -172,7 +176,11 @@ func onWebsocket(w http.ResponseWriter, r *http.Request) {
client_list[wsConn] = &session client_list[wsConn] = &session
Wallet_count[client_list[wsConn].address.String()]++ Wallet_count[client_list[wsConn].address.String()]++
Address = address Address = address
fmt.Printf("%v Incoming connection: %v, Wallet: %v\n", time.Now().Format(time.Stamp), wsConn.RemoteAddr().String(), address) if !config.Pool_mode {
fmt.Printf("%v Incoming connection: %v, Wallet: %v\n", time.Now().Format(time.Stamp), wsConn.RemoteAddr().String(), address)
} else {
fmt.Printf("%v Incoming connection: %v\n", time.Now().Format(time.Stamp), wsConn.RemoteAddr().String())
}
} }
// forward results to daemon // forward results to daemon
@ -207,7 +215,12 @@ func newUpgrader() *websocket.Upgrader {
return return
} else { } else {
go SendToDaemon(data) go SendToDaemon(data)
fmt.Printf("%v Submitting result from miner: %v, Wallet: %v\n", time.Now().Format(time.Stamp), c.RemoteAddr().String(), client_list[c].address.String()) if !config.Pool_mode {
fmt.Printf("%v Submitting result from miner: %v, Wallet: %v\n", time.Now().Format(time.Stamp), c.RemoteAddr().String(), client_list[c].address.String())
} else {
shares++
fmt.Printf("%v Shares submitted: %d\n", time.Now().Format(time.Stamp), shares)
}
} }
}) })