diff --git a/README.md b/README.md index 698d39a..75a70c3 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,15 @@ Long To-Do list, but this is a working release. - muliple wallets are supported - notification of incoming and lost connections / submitted results / stats - user-defined logging interval +- pool mining support (not stratum) **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 --daemon-address: address:port of daemon --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) --nonce (optional): enable random nonces, disabled by default``` +--pool (optional): enable pool mining, disable keyhash replacement \ No newline at end of file diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..93885f5 --- /dev/null +++ b/config/config.go @@ -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 diff --git a/derohe-proxy.go b/derohe-proxy.go index 558ad8a..cf52857 100644 --- a/derohe-proxy.go +++ b/derohe-proxy.go @@ -1,10 +1,12 @@ package main import ( + "derohe-proxy/config" "derohe-proxy/proxy" "fmt" "net" "strconv" + "sync" "time" "github.com/docopt/docopt-go" @@ -12,68 +14,75 @@ import ( func main() { 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 { return } - if Arguments["--listen-address"] != nil { - addr, err := net.ResolveTCPAddr("tcp", Arguments["--listen-address"].(string)) + if config.Arguments["--listen-address"] != nil { + addr, err := net.ResolveTCPAddr("tcp", config.Arguments["--listen-address"].(string)) if err != nil { return } else { if addr.Port == 0 { return } else { - listen_addr = addr.String() + config.Listen_addr = addr.String() } } } - if Arguments["--daemon-address"] == nil { + if config.Arguments["--daemon-address"] == nil { return } else { - daemon_address = Arguments["--daemon-address"].(string) + config.Daemon_address = config.Arguments["--daemon-address"].(string) } - if Arguments["--log-interval"] != nil { - interval, err := strconv.ParseInt(Arguments["--log-interval"].(string), 10, 32) + if config.Arguments["--log-interval"] != nil { + interval, err := strconv.ParseInt(config.Arguments["--log-interval"].(string), 10, 32) if err != nil { return } else { if interval < 60 || interval > 3600 { - log_intervall = 60 + config.Log_intervall = 60 } else { - log_intervall = int(interval) + config.Log_intervall = int(interval) } } } - if Arguments["--minimal"].(bool) { - minimal = true + if config.Arguments["--minimal"].(bool) { + config.Minimal = true fmt.Printf("%v Forward only 2 jobs per block\n", time.Now().Format(time.Stamp)) } - if Arguments["--nonce"].(bool) { - nonce = true + if config.Arguments["--nonce"].(bool) { + config.Nonce = true 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 for proxy.CountMiners() < 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() for { - time.Sleep(time.Second * time.Duration(log_intervall)) + time.Sleep(time.Second * time.Duration(config.Log_intervall)) hash_rate_string := "" @@ -90,11 +99,17 @@ func main() { 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 { if proxy.Wallet_count[i] > 1 { fmt.Printf("%v Wallet %v, %d miners\n", time.Now().Format(time.Stamp), i, proxy.Wallet_count[i]) } } + rwmutex.RUnlock() } } diff --git a/proxy/client.go b/proxy/client.go index 6ae506d..3039795 100644 --- a/proxy/client.go +++ b/proxy/client.go @@ -8,6 +8,8 @@ import ( "net/url" "time" + "derohe-proxy/config" + "github.com/gorilla/websocket" ) @@ -45,7 +47,7 @@ var ModdedNode bool = false var Hashrate float64 // proxy-client -func Start_client(v string, w string, min_jobs bool, nonce bool) { +func Start_client(w string) { var err error var last_diff uint64 var last_height uint64 @@ -54,14 +56,18 @@ func Start_client(v string, w string, min_jobs bool, nonce bool) { 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.TLSClientConfig = &tls.Config{ 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) if err != nil { 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 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 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 { last_height = params.Height last_diff = params.Difficultyuint64 - go SendTemplateToNodes(recv_data, nonce) + go SendTemplateToNodes(recv_data) } } else { - go SendTemplateToNodes(recv_data, nonce) + go SendTemplateToNodes(recv_data) } } } diff --git a/proxy/server.go b/proxy/server.go index 1b74ade..2ad1e22 100644 --- a/proxy/server.go +++ b/proxy/server.go @@ -15,6 +15,8 @@ import ( "sync" "time" + "derohe-proxy/config" + "github.com/deroproject/derohe/globals" "github.com/deroproject/derohe/rpc" "github.com/deroproject/graviton" @@ -57,10 +59,11 @@ var client_list_mutex sync.Mutex var client_list = map[*websocket.Conn]*user_session{} var miners_count int +var shares uint64 var Wallet_count map[string]uint var Address string -func Start_server(listen string) { +func Start_server() { var err error tlsConfig := &tls.Config{ @@ -74,7 +77,7 @@ func Start_server(listen string) { server = nbhttp.NewServer(nbhttp.Config{ Name: "GETWORK", Network: "tcp", - AddrsTLS: []string{listen}, + AddrsTLS: []string{config.Listen_addr}, TLSConfig: tlsConfig, Handler: mux, MaxLoad: 10 * 1024, @@ -110,7 +113,7 @@ func CountMiners() int { } // forward all incoming templates from daemon to all miners -func SendTemplateToNodes(data []byte, nonce bool) { +func SendTemplateToNodes(data []byte) { client_list_mutex.Lock() defer client_list_mutex.Unlock() @@ -121,12 +124,14 @@ func SendTemplateToNodes(data []byte, nonce bool) { 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 { - data = result - } else { - fmt.Println(time.Now().Format(time.Stamp), "Failed to change nonce / miner keyhash") + if result := edit_blob(data, miner_address, config.Nonce); result != nil { + data = result + } else { + fmt.Println(time.Now().Format(time.Stamp), "Failed to change nonce / miner keyhash") + } } go func(k *websocket.Conn, v *user_session) { @@ -137,7 +142,6 @@ func SendTemplateToNodes(data []byte, nonce bool) { }(rk, rv) } - } // handling for incoming miner connections @@ -172,7 +176,11 @@ func onWebsocket(w http.ResponseWriter, r *http.Request) { client_list[wsConn] = &session Wallet_count[client_list[wsConn].address.String()]++ 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 @@ -207,7 +215,12 @@ func newUpgrader() *websocket.Upgrader { return } else { 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) + } } })