parent
7f1b849394
commit
50d206c150
@ -1 +1,2 @@
|
||||
**/build
|
||||
**/docker-compose
|
||||
|
@ -1,42 +0,0 @@
|
||||
##
|
||||
# Monero Wallet Address for mining rewards (replace this with your own address)
|
||||
WALLET_ADDRESS="44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg"
|
||||
|
||||
##
|
||||
# p2pool settings
|
||||
#
|
||||
# Use p2pool-mini (uncomment to enable)
|
||||
#P2POOL_MINI="--mini"
|
||||
#
|
||||
# Which port to listen for miner connections
|
||||
P2POOL_STRATUM_PORT=3333
|
||||
#
|
||||
# How much logging - (Less) 0 - 6 (More)
|
||||
P2POOL_LOGLEVEL=2
|
||||
|
||||
|
||||
##
|
||||
# Monero Node Settings
|
||||
#
|
||||
# Version of Monero to build. Must be v0.17.3.0 or later for p2pool support. "latest" pulls the most recent release tag
|
||||
MONERO_GIT_TAG=latest
|
||||
#
|
||||
# Limit the size of the blockchain on disk (comment to disable)
|
||||
PRUNE_NODE="--prune-blockchain"
|
||||
#
|
||||
# Other monerod commandline options
|
||||
MONERO_EXTRA_OPTIONS=""
|
||||
|
||||
|
||||
##
|
||||
# Xmrig Miner Settings
|
||||
#
|
||||
# Submit shares at a lower fixed difficulty to show mining progress (comment to disable, edit to customize)
|
||||
FIXED_MINING_DIFFICULTY="-u x+500000"
|
||||
#
|
||||
# set process priority (0 idle, 2 normal to 5 highest)
|
||||
MINING_CPU_PRIORITY="--cpu-priority=2"
|
||||
#
|
||||
# Other XMRIG commandline options
|
||||
# See: https://xmrig.com/docs/miner/command-line-options
|
||||
XMRIG_EXTRA_OPTIONS=""
|
@ -0,0 +1,14 @@
|
||||
FROM python:3.10.5-bullseye
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD requirements.txt /app/
|
||||
RUN /usr/local/bin/pip3 install -r requirements.txt
|
||||
|
||||
ADD configure.py /app/
|
||||
ADD defaults /app/
|
||||
ADD current_config.jinja2 /app/
|
||||
ADD docker-compose.jinja2 /app/
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/python3"]
|
||||
CMD ["/app/configure.py"]
|
@ -0,0 +1,951 @@
|
||||
#!/bin/env python3
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
from jinja2 import Template
|
||||
import npyscreen
|
||||
|
||||
# Help text in a box at the bottom of the screen
|
||||
class HelpBoxBase(npyscreen.BoxTitle):
|
||||
def splitlines(self):
|
||||
all_help = []
|
||||
for fld, msg in self.help_msgs.items():
|
||||
if fld[-1] != ":":
|
||||
fld += ":"
|
||||
message = [m.lstrip() for m in msg if m != ""]
|
||||
helpline = f"{fld:<28}{'. '.join(message)}"
|
||||
all_help.append(helpline)
|
||||
all_help.append("")
|
||||
return all_help
|
||||
|
||||
def display_help_message(self, field):
|
||||
self.set_values(
|
||||
self.help_msgs.get(field, "No help availabe for {}".format(field))
|
||||
)
|
||||
self.clear()
|
||||
self.display()
|
||||
|
||||
|
||||
class P2PoolHelpBox(HelpBoxBase):
|
||||
help_msgs = {
|
||||
"Wallet Address:": [
|
||||
"Your monero wallet address for receiving mining reqards",
|
||||
"",
|
||||
"Note: You have to use a primary wallet address for mining",
|
||||
" Subaddresses and integrated addresses are not supported!",
|
||||
],
|
||||
"P2Pool Sidechain:": [
|
||||
"Which P2Pool sidechain to mine on",
|
||||
" use main for faster miners",
|
||||
" use mini for slower miners",
|
||||
],
|
||||
"Enable Server Statistics": [
|
||||
"Provide access to your P2Pool server statictics via a web interface",
|
||||
],
|
||||
"Statistics Port:": [
|
||||
"Port number (or IP:Port) to expose web access to your P2Pool server",
|
||||
"statictics",
|
||||
],
|
||||
"Expose Stratum Port": [
|
||||
"Expose the P2Pool stratum port to your network so external miners",
|
||||
"can connect",
|
||||
"Note: You may choose to open this port in your hosts firewall and/or",
|
||||
" router to allow miners outside your network to connect",
|
||||
],
|
||||
"Stratum Port:": [
|
||||
"Port number (or IP:Port) to expose P2Pool stratum to your network to",
|
||||
"allow external miners to connect",
|
||||
"Note: You may choose to open this port in your hosts firewall and/or",
|
||||
" router to allow miners outside your network to connect",
|
||||
],
|
||||
"P2Pool Log Level:": [
|
||||
"Verbosity of the log; (Less) 0 - 6 (More)",
|
||||
],
|
||||
"Enable Autodiff": [
|
||||
"Use automatic difficulty adjustment for miners connected to stratum",
|
||||
],
|
||||
"Enable Light Mode": [
|
||||
"Don't allocate RandomX dataset, saves 2GB of RAM",
|
||||
],
|
||||
"Disable Cache": [
|
||||
"Disable p2pool.cache (not recommended)",
|
||||
],
|
||||
"Additional P2Pool Options:": [
|
||||
"Additional options to pass to p2pool commandline",
|
||||
"",
|
||||
"Note: Advanced - Only add options if you know what you are doing",
|
||||
" See ouput of 'p2pool --help' for available options",
|
||||
],
|
||||
"Next": [
|
||||
"Next configuration menu",
|
||||
],
|
||||
"Save": [
|
||||
"Save current configuration and exit",
|
||||
],
|
||||
"Cancel": [
|
||||
"Exit without saving",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class MoneroHelpBox(HelpBoxBase):
|
||||
help_msgs = {
|
||||
"Configure Monero Node": [
|
||||
"Configure and run a Monero Node",
|
||||
"",
|
||||
"Note: You must either configure a local node or specify a public node",
|
||||
],
|
||||
"Monero Version:": [
|
||||
"Version of Monero to build; 'latest' for the most recent release",
|
||||
"",
|
||||
"Note: Must be v0.17.3.0 or later for p2pool support",
|
||||
" See: https://github.com/monero-project/monero/tags",
|
||||
],
|
||||
"Prune Blockchain": [
|
||||
"Prune the Monero node to limit the size of the blockchain on disk",
|
||||
],
|
||||
"Monero Log Level:": [
|
||||
"Verbosity of the log; (Less) 0 - 4 (More)",
|
||||
"",
|
||||
"Note: settings above 0 are very noisy",
|
||||
],
|
||||
"Expose RPC Port": [
|
||||
"Expose restricted RPC API port to your network so external services",
|
||||
"(wallets for example) can connect",
|
||||
"Note: You may choose to open this port in your hosts firewall and/or",
|
||||
" router to allow services outside your network to connect",
|
||||
],
|
||||
"RPC Port:": [
|
||||
"TCP port to listen on for RPC connections",
|
||||
],
|
||||
"RPC Login:": [
|
||||
"Specify username[:password] required to connect to the RPC API",
|
||||
],
|
||||
"Limit Data Rates": [
|
||||
"Set a limit value for incoming and outgoing data transfer",
|
||||
],
|
||||
"Rate Limit Up:": [
|
||||
"Set outgoing data transfer limit [kB/s]",
|
||||
],
|
||||
"Rate Limit Down:": [
|
||||
"Set incoming data transfer limit [kB/s]",
|
||||
],
|
||||
"Sync Pruned Blocks": [
|
||||
"Accept pruned blocks instead of pruning yourself to save",
|
||||
"network transfer",
|
||||
],
|
||||
"Fast Block Sync": [
|
||||
'Sync up most of the way by using embedded, "known" (old) block',
|
||||
"hashes without calculating the block hash to verify the proof of work",
|
||||
"",
|
||||
"Note: Faster initial sync by trusting the monerod binary",
|
||||
],
|
||||
"Public Node:": [
|
||||
"Public Monero Node to Use",
|
||||
"",
|
||||
"Note: The public node must have both Monero RPC and zmq-pub ports",
|
||||
" available",
|
||||
],
|
||||
"Node Login:": [
|
||||
"Specify username[:password] required to connect to public monero",
|
||||
"node RPC API (if required)",
|
||||
],
|
||||
"Additional monerod Options:": [
|
||||
"Additional options to pass to monerod commandline",
|
||||
"",
|
||||
"Note: Advanced - Only add options if you know what you are doing",
|
||||
" See 'https://monerodocs.org/interacting/monerod-reference/'",
|
||||
],
|
||||
"Prev": [
|
||||
"Previous configuration menu",
|
||||
],
|
||||
"Next": [
|
||||
"Next configuration menu",
|
||||
],
|
||||
"Save": [
|
||||
"Save current configuration and exit",
|
||||
],
|
||||
"Cancel": [
|
||||
"Exit without saving",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class XMRigHelpBox(HelpBoxBase):
|
||||
help_msgs = {
|
||||
"Configure XMRig CPU Miner": [
|
||||
"Configure and run an XMRig CPU Miner",
|
||||
"",
|
||||
"Note: You must either configure am XMRig CPU Miner or expose the",
|
||||
" P2Pool stratum port and connect an external miner, or both",
|
||||
],
|
||||
"Username:": [
|
||||
"Set a username for the miner",
|
||||
],
|
||||
"Use Fixed Difficulty": [
|
||||
"Used a fixed minig difficulty",
|
||||
"",
|
||||
"Note: Allows you to see XMRig submitting shares below P2Pool threshold",
|
||||
],
|
||||
"Fixed Difficulty:": [
|
||||
"Set a fixed mining difficulty",
|
||||
"",
|
||||
"Note: Allows you to see XMRig submitting shares below P2Pool threshold",
|
||||
],
|
||||
"CPU Use %:": [
|
||||
"Maximum CPU threads count (in percentage) hint for autoconfig",
|
||||
"Note: Applies to cores only. If you have HyperThreading enabled you",
|
||||
" should divide this value by 2 (use 0-50%). Reference:",
|
||||
" https://github.com/xmrig/xmrig/issues/1670#issuecomment-644433778",
|
||||
],
|
||||
"CPU Priority:": [
|
||||
"Set process priority (0 idle, 2 normal to 5 highest)",
|
||||
],
|
||||
"Additional XMRig Options:": [
|
||||
"Additional options to pass to xmrig",
|
||||
"",
|
||||
"Note: Advanced - Only add options if you know what you are doing",
|
||||
" See 'https://xmrig.com/docs/miner/command-line-options'",
|
||||
],
|
||||
"Prev": [
|
||||
"Previous configuration menu",
|
||||
],
|
||||
"Save": [
|
||||
"Save current configuration and exit",
|
||||
],
|
||||
"Cancel": [
|
||||
"Exit without saving",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
##
|
||||
# Custom (integer) values for title slider
|
||||
class IntegerSlider(npyscreen.Slider):
|
||||
def translate_value(self):
|
||||
from_val = int(str(self.value).split(".")[0])
|
||||
out_of_val = int(str(self.out_of).split(".")[0])
|
||||
if from_val >= 1000:
|
||||
from_val = str(from_val / 1000).split(".")[0] + "K"
|
||||
out_of_val = str(out_of_val / 1000).split(".")[0] + "K"
|
||||
return "{}/{}".format(from_val, out_of_val)
|
||||
|
||||
|
||||
class TitleIntegerSlider(npyscreen.TitleSlider):
|
||||
_entry_type = IntegerSlider
|
||||
|
||||
|
||||
##
|
||||
# Patched updateDependents for FormControlCheckbox
|
||||
class PatchedFormControlCheckbox(npyscreen.FormControlCheckbox):
|
||||
def updateDependents(self):
|
||||
if self.value:
|
||||
for w in self._visibleWhenSelected:
|
||||
try:
|
||||
w.fc_visible
|
||||
except AttributeError:
|
||||
w.fc_visible = {}
|
||||
w.fc_visible[self.name] = True
|
||||
for w in self._notVisibleWhenSelected:
|
||||
try:
|
||||
w.fc_visible
|
||||
except AttributeError:
|
||||
w.fc_visible = {}
|
||||
w.fc_visible[self.name] = False
|
||||
else:
|
||||
for w in self._visibleWhenSelected:
|
||||
try:
|
||||
w.fc_visible
|
||||
except AttributeError:
|
||||
w.fc_visible = {}
|
||||
w.fc_visible[self.name] = False
|
||||
for w in self._notVisibleWhenSelected:
|
||||
try:
|
||||
w.fc_visible
|
||||
except AttributeError:
|
||||
w.fc_visible = {}
|
||||
w.fc_visible[self.name] = True
|
||||
for w in self._visibleWhenSelected + self._notVisibleWhenSelected:
|
||||
w.hidden = False in w.fc_visible.values()
|
||||
w.editable = not False in w.fc_visible.values()
|
||||
self.parent.display()
|
||||
|
||||
def set_value(self, value):
|
||||
self.value = value
|
||||
self.display()
|
||||
|
||||
def display(self):
|
||||
self.updateDependents()
|
||||
super()
|
||||
|
||||
|
||||
class PrevButton(npyscreen.Button):
|
||||
def whenToggled(self):
|
||||
self.value = False
|
||||
self.parent.prev_form()
|
||||
|
||||
|
||||
class NextButton(npyscreen.Button):
|
||||
def whenToggled(self):
|
||||
self.value = False
|
||||
self.parent.next_form()
|
||||
|
||||
|
||||
class SaveButton(npyscreen.Button):
|
||||
def whenToggled(self):
|
||||
self.find_parent_app().save_and_exit()
|
||||
|
||||
|
||||
class CancelButton(npyscreen.Button):
|
||||
def whenToggled(self):
|
||||
self.find_parent_app().cancel_and_exit()
|
||||
|
||||
|
||||
##
|
||||
# Config Forms Base Class
|
||||
class ConfigFormBase(npyscreen.FormBaseNew):
|
||||
name_size = 20
|
||||
indent = 5
|
||||
current_config = None
|
||||
defaults = None
|
||||
ALLOW_RESIZE = False
|
||||
|
||||
def while_editing(self, arg):
|
||||
self.help.display_help_message(arg.name)
|
||||
self.display()
|
||||
|
||||
def get_default_config(self):
|
||||
# Return defaults
|
||||
if self.defaults is None:
|
||||
with open("defaults") as defaults_file:
|
||||
self.defaults = json.load(defaults_file)
|
||||
return self.defaults
|
||||
|
||||
def get_current_config(self):
|
||||
# Return current config
|
||||
if self.current_config is None:
|
||||
# Read current config
|
||||
with open("/docker-compose/current_config") as current_config:
|
||||
self.current_config = json.load(current_config)
|
||||
return self.current_config
|
||||
|
||||
def reset_defaults(self, arg):
|
||||
# Set config to default values
|
||||
ok = npyscreen.notify_ok_cancel(
|
||||
"Set current form values to defaults", title="Reset to Defaults"
|
||||
)
|
||||
if not ok:
|
||||
return
|
||||
defaults = self.get_default_config()
|
||||
self.set_config(defaults)
|
||||
|
||||
|
||||
##
|
||||
# P2Pool Configuration Form
|
||||
class P2PoolConfigForm(ConfigFormBase):
|
||||
def create(self):
|
||||
# Add Hot-Key Controls
|
||||
self.add_handlers({"^D": self.reset_defaults})
|
||||
# Add P2Pool Configuration
|
||||
self.add(
|
||||
npyscreen.TitleText,
|
||||
name="## P2Pool Configuration",
|
||||
editable=False,
|
||||
begin_entry_at=50,
|
||||
)
|
||||
self.wallet_address = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Wallet Address:",
|
||||
value="",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.nextrely += 1
|
||||
self.sidechain = self.add(
|
||||
npyscreen.TitleSelectOne,
|
||||
name="P2Pool Sidechain:",
|
||||
values=["main", "mini"],
|
||||
scroll_exit=True,
|
||||
max_height=2,
|
||||
value=[
|
||||
0,
|
||||
],
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.nextrely += 1
|
||||
self.enable_statistics = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Enable Server Statistics",
|
||||
value=True,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.statistics_port = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Statistics Port:",
|
||||
value="3334",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.enable_statistics.addVisibleWhenSelected(self.statistics_port)
|
||||
self.nextrely += 1
|
||||
self.expose_stratum_port = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Expose Stratum Port",
|
||||
value=True,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.stratum_port = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Stratum Port:",
|
||||
value="3333",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.expose_stratum_port.addVisibleWhenSelected(self.stratum_port)
|
||||
self.nextrely += 1
|
||||
self.p2pool_log_level = self.add(
|
||||
TitleIntegerSlider,
|
||||
name="P2Pool Log Level:",
|
||||
out_of=6,
|
||||
value=3,
|
||||
lowest=0,
|
||||
step=1,
|
||||
width=43,
|
||||
begin_entry_at=20,
|
||||
label=True,
|
||||
block_color=None,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.nextrely += 1
|
||||
self.autodiff = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Enable Autodiff",
|
||||
value=True,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.nextrely += 1
|
||||
self.light_mode = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Enable Light Mode",
|
||||
value=False,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.nextrely += 1
|
||||
self.no_cache = self.add(
|
||||
npyscreen.Checkbox,
|
||||
name="Disable Cache",
|
||||
value=False,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.nextrely += 1
|
||||
self.p2pool_extra = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Additional P2Pool Options:",
|
||||
value="",
|
||||
begin_entry_at=self.name_size + 10,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.nextrely += 1
|
||||
self.nextrely += 1
|
||||
# Add "Next", "Save", and "Cancel" buttons
|
||||
self.next_button = self.add(NextButton, name="Next", relx=1)
|
||||
self.nextrely -= 1
|
||||
self.save_button = self.add(SaveButton, name="Save", relx=8)
|
||||
self.nextrely -= 1
|
||||
self.cancel_button = self.add(CancelButton, name="Cancel", relx=15)
|
||||
self.nextrely += 1
|
||||
# Add Help Box
|
||||
self.help = self.add(
|
||||
P2PoolHelpBox,
|
||||
name="Commands: ^D: Load Defaults - ^C: Exit Without Saving",
|
||||
values=[""],
|
||||
editable=False,
|
||||
)
|
||||
# Start with current config
|
||||
self.set_config(self.get_current_config())
|
||||
|
||||
def next_form(self):
|
||||
self.find_parent_app().switchForm("MONERO")
|
||||
|
||||
def set_config(self, config):
|
||||
self.wallet_address.set_value(config["wallet_address"])
|
||||
self.sidechain.set_value(config["sidechain"])
|
||||
self.enable_statistics.set_value(config["enable_statistics"])
|
||||
self.statistics_port.set_value(config["statistics_port"])
|
||||
self.expose_stratum_port.set_value(config["expose_stratum_port"])
|
||||
self.stratum_port.set_value(config["stratum_port"])
|
||||
self.p2pool_log_level.set_value(config["p2pool_log_level"])
|
||||
self.autodiff.set_value(config["enable_autodiff"])
|
||||
self.light_mode.set_value(config["light_mode"])
|
||||
self.no_cache.value = config["no_cache"]
|
||||
self.p2pool_extra.set_value(config["p2pool_options"])
|
||||
self.DISPLAY()
|
||||
|
||||
def get_config(self):
|
||||
config = {
|
||||
"wallet_address": self.wallet_address.value,
|
||||
"sidechain": self.sidechain.value,
|
||||
"enable_statistics": self.enable_statistics.value,
|
||||
"statistics_port": self.statistics_port.value,
|
||||
"expose_stratum_port": self.expose_stratum_port.value,
|
||||
"stratum_port": self.stratum_port.value,
|
||||
"p2pool_log_level": self.p2pool_log_level.value,
|
||||
"enable_autodiff": self.autodiff.value,
|
||||
"light_mode": self.light_mode.value,
|
||||
"no_cache": self.no_cache.value,
|
||||
"p2pool_options": self.p2pool_extra.value,
|
||||
}
|
||||
return config
|
||||
|
||||
|
||||
##
|
||||
# Monero Configuration Form
|
||||
class MoneroConfigForm(ConfigFormBase):
|
||||
def create(self):
|
||||
# Add Hot-Key Controls
|
||||
self.add_handlers({"^D": self.reset_defaults})
|
||||
# Add Monero Configuration
|
||||
self.add(
|
||||
npyscreen.TitleText,
|
||||
name="## Monero Node Configuration",
|
||||
editable=False,
|
||||
begin_entry_at=50,
|
||||
)
|
||||
self.configure_monero_node = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Configure Monero Node",
|
||||
value=True,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.nextrely += 1
|
||||
self.monero_git_tag = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Monero Version:",
|
||||
value="latest",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.monero_git_tag)
|
||||
self.prune_node = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Prune Blockchain",
|
||||
value=True,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.prune_node)
|
||||
self.monero_log_level = self.add(
|
||||
TitleIntegerSlider,
|
||||
name="Monero Log Level:",
|
||||
out_of=4,
|
||||
value=0,
|
||||
lowest=0,
|
||||
step=1,
|
||||
width=43,
|
||||
begin_entry_at=20,
|
||||
label=True,
|
||||
block_color=None,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.monero_log_level)
|
||||
self.nextrely += 1
|
||||
self.expose_rpc_port = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Expose RPC Port",
|
||||
value=False,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.expose_rpc_port)
|
||||
self.rpc_port = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="RPC Port:",
|
||||
value="18081",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.rpc_port)
|
||||
self.expose_rpc_port.addVisibleWhenSelected(self.rpc_port)
|
||||
self.rpc_login = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="RPC Login:",
|
||||
value="",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.expose_rpc_port.addVisibleWhenSelected(self.rpc_login)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.rpc_login)
|
||||
self.nextrely += 1
|
||||
self.limit_data_rates = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Limit Data Rates",
|
||||
value=False,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.limit_data_rates)
|
||||
self.rate_limit_up = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Rate Limit Up:",
|
||||
value="2048",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.limit_data_rates.addVisibleWhenSelected(self.rate_limit_up)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.rate_limit_up)
|
||||
self.rate_limit_down = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Rate Limit Down:",
|
||||
value="8192",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.limit_data_rates.addVisibleWhenSelected(self.rate_limit_down)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.rate_limit_down)
|
||||
self.nextrely += 1
|
||||
self.sync_pruned_blocks = self.add(
|
||||
npyscreen.Checkbox,
|
||||
name="Sync Pruned Blocks",
|
||||
value=False,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.sync_pruned_blocks)
|
||||
self.prune_node.addVisibleWhenSelected(self.sync_pruned_blocks)
|
||||
self.fast_sync = self.add(
|
||||
npyscreen.Checkbox,
|
||||
name="Fast Block Sync",
|
||||
value=False,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.fast_sync)
|
||||
self.nextrely += 1
|
||||
self.public_node = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Public Node:",
|
||||
value="",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addInvisibleWhenSelected(self.public_node)
|
||||
self.node_login = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Node Login:",
|
||||
value="",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addInvisibleWhenSelected(self.node_login)
|
||||
self.nextrely += 1
|
||||
self.monero_extra = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Additional monerod Options:",
|
||||
value="",
|
||||
begin_entry_at=self.name_size + 10,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_monero_node.addVisibleWhenSelected(self.monero_extra)
|
||||
self.nextrely += 1
|
||||
self.nextrely += 1
|
||||
# Add "Prev", "Next", "Save", and "Cancel" buttons
|
||||
self.prev_button = self.add(PrevButton, name="Prev", relx=1)
|
||||
self.nextrely -= 1
|
||||
self.next_button = self.add(NextButton, name="Next", relx=8)
|
||||
self.nextrely -= 1
|
||||
self.save_button = self.add(SaveButton, name="Save", relx=15)
|
||||
self.nextrely -= 1
|
||||
self.cancel_button = self.add(CancelButton, name="Cancel", relx=22)
|
||||
self.nextrely += 1
|
||||
# Add Help Box
|
||||
self.help = self.add(
|
||||
MoneroHelpBox,
|
||||
name="Commands: ^D: Load Defaults - ^C: Exit Without Saving",
|
||||
values=[""],
|
||||
editable=False,
|
||||
)
|
||||
# Start with current config
|
||||
self.set_config(self.get_current_config())
|
||||
|
||||
def prev_form(self):
|
||||
self.find_parent_app().switchForm("MAIN")
|
||||
|
||||
def next_form(self):
|
||||
self.find_parent_app().switchForm("XMRIG")
|
||||
|
||||
def set_config(self, config):
|
||||
self.configure_monero_node.set_value(config["configure_monero"])
|
||||
self.monero_git_tag.set_value(config["monero_version"])
|
||||
self.prune_node.value = config["prune_blockchain"]
|
||||
self.monero_log_level.set_value(config["monero_log_level"])
|
||||
self.expose_rpc_port.set_value(config["expose_rpc_port"])
|
||||
self.rpc_port.set_value(config["rpc_port"])
|
||||
self.rpc_login.set_value(config["rpc_login"])
|
||||
self.limit_data_rates.set_value(config["limit_data_rates"])
|
||||
self.rate_limit_up.set_value(config["rate_limit_up"])
|
||||
self.rate_limit_down.set_value(config["rate_limit_down"])
|
||||
self.sync_pruned_blocks.value = config["sync_pruned_blocks"]
|
||||
self.fast_sync.value = config["fast_sync"]
|
||||
self.monero_extra.set_value(config["monero_options"])
|
||||
self.public_node.set_value(config["public_monero_node"])
|
||||
self.node_login.set_value(config["monero_node_login"])
|
||||
self.DISPLAY()
|
||||
|
||||
def get_config(self):
|
||||
config = {
|
||||
"configure_monero": self.configure_monero_node.value,
|
||||
"monero_version": self.monero_git_tag.value,
|
||||
"prune_blockchain": self.prune_node.value,
|
||||
"monero_log_level": self.monero_log_level.value,
|
||||
"expose_rpc_port": self.expose_rpc_port.value,
|
||||
"rpc_port": self.rpc_port.value,
|
||||
"rpc_login": self.rpc_login.value,
|
||||
"limit_data_rates": self.limit_data_rates.value,
|
||||
"rate_limit_up": self.rate_limit_up.value,
|
||||
"rate_limit_down": self.rate_limit_down.value,
|
||||
"sync_pruned_blocks": self.sync_pruned_blocks.value,
|
||||
"fast_sync": self.fast_sync.value,
|
||||
"monero_options": self.monero_extra.value,
|
||||
"public_monero_node": self.public_node.value,
|
||||
"monero_node_login": self.node_login.value,
|
||||
}
|
||||
return config
|
||||
|
||||
|
||||
##
|
||||
# XMRig Configuration Form
|
||||
class XMRigConfigForm(ConfigFormBase):
|
||||
def create(self):
|
||||
# Add Hot-Key Controls
|
||||
self.add_handlers({"^D": self.reset_defaults})
|
||||
# Hidden caryover from P2Pool form
|
||||
self.autodiff = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Enable Autodiff",
|
||||
value=True,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.autodiff.hide = True
|
||||
self.autodiff.editable = False
|
||||
self.nextrely -= 1
|
||||
# Add XMRig Configuration
|
||||
self.add(
|
||||
npyscreen.TitleText,
|
||||
name="## XMRig Miner Configuration",
|
||||
editable=False,
|
||||
begin_entry_at=50,
|
||||
)
|
||||
self.configure_xmrig_miner = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Configure XMRig CPU Miner",
|
||||
value=True,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.nextrely += 1
|
||||
self.username = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Username:",
|
||||
value="",
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_xmrig_miner.addVisibleWhenSelected(self.username)
|
||||
self.nextrely += 1
|
||||
self.use_fixed_difficulty = self.add(
|
||||
PatchedFormControlCheckbox,
|
||||
name="Use Fixed Difficulty",
|
||||
value=True,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_xmrig_miner.addVisibleWhenSelected(self.use_fixed_difficulty)
|
||||
self.autodiff.addInvisibleWhenSelected(self.use_fixed_difficulty)
|
||||
self.fixed_difficulty = self.add(
|
||||
TitleIntegerSlider,
|
||||
name="Fixed Difficulty:",
|
||||
out_of=2000000,
|
||||
value=500000,
|
||||
lowest=50000,
|
||||
step=50000,
|
||||
width=51,
|
||||
begin_entry_at=20,
|
||||
label=True,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_xmrig_miner.addVisibleWhenSelected(self.fixed_difficulty)
|
||||
self.use_fixed_difficulty.addVisibleWhenSelected(self.fixed_difficulty)
|
||||
self.autodiff.addInvisibleWhenSelected(self.fixed_difficulty)
|
||||
self.nextrely += 1
|
||||
self.cpu_threads = self.add(
|
||||
TitleIntegerSlider,
|
||||
name="CPU Use %:",
|
||||
out_of=100,
|
||||
value=100,
|
||||
lowest=1,
|
||||
step=10,
|
||||
width=48,
|
||||
begin_entry_at=20,
|
||||
label=True,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_xmrig_miner.addVisibleWhenSelected(self.cpu_threads)
|
||||
self.nextrely += 1
|
||||
self.cpu_priority = self.add(
|
||||
TitleIntegerSlider,
|
||||
name="CPU Priority:",
|
||||
out_of=5,
|
||||
value=2,
|
||||
lowest=0,
|
||||
step=1,
|
||||
width=48,
|
||||
begin_entry_at=20,
|
||||
label=True,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_xmrig_miner.addVisibleWhenSelected(self.cpu_priority)
|
||||
self.nextrely += 1
|
||||
self.xmrig_extra = self.add(
|
||||
npyscreen.TitleText,
|
||||
name="Additional XMRig Options:",
|
||||
value="",
|
||||
begin_entry_at=self.name_size + 10,
|
||||
relx=self.indent,
|
||||
)
|
||||
self.configure_xmrig_miner.addVisibleWhenSelected(self.xmrig_extra)
|
||||
self.nextrely += 1
|
||||
self.nextrely += 1
|
||||
# Add "Prev", "Save", and "Cancel" buttons
|
||||
self.prev_button = self.add(PrevButton, name="Prev", relx=1)
|
||||
self.nextrely -= 1
|
||||
self.save_button = self.add(SaveButton, name="Save", relx=8)
|
||||
self.nextrely -= 1
|
||||
self.cancel_button = self.add(CancelButton, name="Cancel", relx=15)
|
||||
self.nextrely += 1
|
||||
# Add Help Box
|
||||
self.help = self.add(
|
||||
XMRigHelpBox,
|
||||
name="Commands: ^D: Load Defaults - ^C: Exit Without Saving",
|
||||
values=[""],
|
||||
editable=False,
|
||||
)
|
||||
# Start with current config
|
||||
self.set_config(self.get_current_config())
|
||||
|
||||
def prev_form(self):
|
||||
self.find_parent_app().switchForm("MONERO")
|
||||
|
||||
def next_form(self):
|
||||
self.find_parent_app().switchForm(None)
|
||||
|
||||
def beforeEditing(self):
|
||||
# Cary autodiff value from P2Pool config form
|
||||
enable_autodiff = self.find_parent_app().get_p2pool_config()["enable_autodiff"]
|
||||
self.autodiff.set_value(enable_autodiff)
|
||||
|
||||
def set_config(self, config):
|
||||
self.configure_xmrig_miner.set_value(config["configure_xmrig"])
|
||||
self.username.set_value(config["xmrig_username"])
|
||||
self.use_fixed_difficulty.set_value(config["use_fixed_difficulty"])
|
||||
self.fixed_difficulty.set_value(config["fixed_difficulty"])
|
||||
self.cpu_threads.set_value(config["cpu_percent"])
|
||||
self.cpu_priority.set_value(config["cpu_priority"])
|
||||
self.xmrig_extra.set_value(config["xmrig_options"])
|
||||
self.DISPLAY()
|
||||
|
||||
def get_config(self):
|
||||
config = {
|
||||
"configure_xmrig": self.configure_xmrig_miner.value,
|
||||
"xmrig_username": self.username.value,
|
||||
"use_fixed_difficulty": self.use_fixed_difficulty.value,
|
||||
"fixed_difficulty": self.fixed_difficulty.value,
|
||||
"cpu_percent": self.cpu_threads.value,
|
||||
"cpu_priority": self.cpu_priority.value,
|
||||
"xmrig_options": self.xmrig_extra.value,
|
||||
}
|
||||
return config
|
||||
|
||||
|
||||
##
|
||||
# Our P2Pool configuration App
|
||||
class ConfigApp(npyscreen.NPSAppManaged):
|
||||
current_config = None
|
||||
defaults = None
|
||||
|
||||
def onStart(self):
|
||||
self.p2pool_form = self.addForm(
|
||||
"MAIN",
|
||||
P2PoolConfigForm,
|
||||
name="P2Pool for docker-compose: P2Pool Configuration",
|
||||
minimum_lines=35,
|
||||
minimum_columns=80,
|
||||
)
|
||||
self.monero_form = self.addForm(
|
||||
"MONERO",
|
||||
MoneroConfigForm,
|
||||
name="P2Pool for docker-compose: Monero Configuration",
|
||||
minimum_lines=35,
|
||||
minimum_columns=80,
|
||||
)
|
||||
self.xmrig_form = self.addForm(
|
||||
"XMRIG",
|
||||
XMRigConfigForm,
|
||||
name="P2Pool for docker-compose: XMRig Configuration",
|
||||
minimum_lines=35,
|
||||
minimum_columns=80,
|
||||
)
|
||||
|
||||
def get_p2pool_config(self):
|
||||
return self.p2pool_form.get_config()
|
||||
|
||||
def get_config(self):
|
||||
p2pool_config = self.p2pool_form.get_config()
|
||||
monero_config = self.monero_form.get_config()
|
||||
xmrig_config = self.xmrig_form.get_config()
|
||||
return p2pool_config | monero_config | xmrig_config
|
||||
|
||||
def save_and_exit(self):
|
||||
# Get config from all forms
|
||||
config = self.get_config()
|
||||
# Save "current config" values file
|
||||
with open("current_config.jinja2", "r") as current_config:
|
||||
template = current_config.read()
|
||||
rendered = Template(template).render(config)
|
||||
with open("/docker-compose/current_config", "w") as current_config:
|
||||
current_config.write(rendered)
|
||||
# Render and save docker-compose file
|
||||
with open("docker-compose.jinja2", "r") as compose_file:
|
||||
template = compose_file.read()
|
||||
rendered = Template(template).render(config, trim_blocks=True)
|
||||
with open("/docker-compose/docker-compose.yml", "w") as compose_file:
|
||||
compose_file.write(rendered)
|
||||
npyscreen.notify("Saved current settings", title="Saved")
|
||||
self.switchForm(None)
|
||||
self.saved = True
|
||||
|
||||
def cancel_and_exit(self):
|
||||
self.switchForm(None)
|
||||
self.saved = False
|
||||
|
||||
|
||||
##
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
time.sleep(1) # Give docker a second to initialize the terminal
|
||||
App = ConfigApp()
|
||||
App.run()
|
||||
print("\n\n")
|
||||
if App.saved:
|
||||
print("Configuration Saved")
|
||||
else:
|
||||
print("Configuration Aborted")
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
print("Configuration Aborted")
|
||||
sys.exit(1)
|
@ -0,0 +1,35 @@
|
||||
{
|
||||
"wallet_address": {{ wallet_address | tojson(indent=2) }},
|
||||
"configure_monero": {{ configure_monero | tojson(indent=2) }},
|
||||
"configure_xmrig": {{ configure_xmrig | tojson(indent=2) }},
|
||||
"sidechain": {{ sidechain | tojson(indent=2) }},
|
||||
"enable_statistics": {{ enable_statistics | tojson(indent=2) }},
|
||||
"statistics_port": {{ statistics_port | tojson(indent=2) }},
|
||||
"expose_stratum_port": {{ expose_stratum_port | tojson(indent=2) }},
|
||||
"stratum_port": {{ stratum_port | tojson(indent=2) }},
|
||||
"p2pool_log_level": {{ p2pool_log_level | int | tojson(indent=2) }},
|
||||
"enable_autodiff": {{ enable_autodiff | tojson(indent=2) }},
|
||||
"light_mode": {{ light_mode | tojson(indent=2) }},
|
||||
"no_cache": {{ no_cache | tojson(indent=2) }},
|
||||
"p2pool_options": {{ p2pool_options | tojson(indent=2) }},
|
||||
"monero_version": {{ monero_version | tojson(indent=2) }},
|
||||
"prune_blockchain": {{ prune_blockchain | tojson(indent=2) }},
|
||||
"monero_log_level": {{ monero_log_level | int | tojson(indent=2) }},
|
||||
"expose_rpc_port": {{ expose_rpc_port | tojson(indent=2) }},
|
||||
"rpc_port": {{ rpc_port | tojson(indent=2) }},
|
||||
"rpc_login": {{ rpc_login | tojson(indent=2) }},
|
||||
"limit_data_rates": {{ limit_data_rates | tojson(indent=2) }},
|
||||
"rate_limit_up": {{ rate_limit_up | tojson(indent=2) }},
|
||||
"rate_limit_down": {{ rate_limit_down | tojson(indent=2) }},
|
||||
"sync_pruned_blocks": {{ sync_pruned_blocks | tojson(indent=2) }},
|
||||
"fast_sync": {{ fast_sync | tojson(indent=2) }},
|
||||
"monero_options": {{ monero_options | tojson(indent=2) }},
|
||||
"public_monero_node": {{ public_monero_node | tojson(indent=2) }},
|
||||
"monero_node_login": {{ monero_node_login | tojson(indent=2) }},
|
||||
"xmrig_username": {{ xmrig_username | tojson(indent=2) }},
|
||||
"use_fixed_difficulty": {{ use_fixed_difficulty | tojson(indent=2) }},
|
||||
"fixed_difficulty": {{ fixed_difficulty | int | tojson(indent=2) }},
|
||||
"cpu_percent": {{ cpu_percent | int | tojson(indent=2) }},
|
||||
"cpu_priority": {{ cpu_priority | int | tojson(indent=2) }},
|
||||
"xmrig_options": {{ xmrig_options | tojson(indent=2) }}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
{
|
||||
"wallet_address": "44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg",
|
||||
"configure_monero": true,
|
||||
"configure_xmrig": true,
|
||||
"sidechain": [0],
|
||||
"enable_statistics": true,
|
||||
"statistics_port": "3380",
|
||||
"expose_stratum_port": false,
|
||||
"stratum_port": "3333",
|
||||
"p2pool_log_level": 3,
|
||||
"enable_autodiff": true,
|
||||
"light_mode": false,
|
||||
"no_cache": false,
|
||||
"p2pool_options": "",
|
||||
"monero_version": "latest",
|
||||
"prune_blockchain": true,
|
||||
"monero_log_level": 0,
|
||||
"expose_rpc_port": false,
|
||||
"rpc_port": "18081",
|
||||
"rpc_login": "",
|
||||
"limit_data_rates": false,
|
||||
"rate_limit_up": "2048",
|
||||
"rate_limit_down": "8192",
|
||||
"sync_pruned_blocks": false,
|
||||
"fast_sync": false,
|
||||
"monero_options": "",
|
||||
"public_monero_node": "",
|
||||
"monero_node_login": "",
|
||||
"xmrig_username": "p2pool",
|
||||
"use_fixed_difficulty": true,
|
||||
"fixed_difficulty": 500000,
|
||||
"cpu_percent": 100,
|
||||
"cpu_priority": 2,
|
||||
"xmrig_options": ""
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
---
|
||||
version: '3.4'
|
||||
|
||||
networks:
|
||||
p2pool:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
p2pool:
|
||||
name: p2pool
|
||||
{% if configure_monero == True %}
|
||||
monero:
|
||||
name: monero
|
||||
{% endif %}
|
||||
|
||||
services:
|
||||
p2pool:
|
||||
image: p2pool:latest
|
||||
build: ../
|
||||
container_name: p2pool-p2pool
|
||||
networks:
|
||||
- p2pool
|
||||
privileged: true
|
||||
ports:
|
||||
{% if sidechain[0] == 0 %}
|
||||
- 37888:37888/tcp
|
||||
{% else %}
|
||||
- 37889:37889/tcp
|
||||
{% endif %}
|
||||
{% if expose_stratum_port == True %}
|
||||
- {{ stratum_port }}:3333/tcp
|
||||
{% endif %}
|
||||
volumes:
|
||||
- p2pool:/home/p2pool/.p2pool:rw
|
||||
- /dev/null:/home/p2pool/.p2pool/p2pool.log:rw
|
||||
- /dev/hugepages:/dev/hugepages:rw
|
||||
{% if configure_monero == True %}
|
||||
depends_on:
|
||||
monero:
|
||||
condition: service_healthy
|
||||
{% endif %}
|
||||
restart: unless-stopped
|
||||
command: >-
|
||||
{% if configure_monero == True %}
|
||||
--host monero
|
||||
{% else %}
|
||||
--host {{ public_monero_node }}
|
||||
--rpc-login {{ monero_node_login }}
|
||||
{% endif %}
|
||||
--wallet {{ wallet_address }}
|
||||
--loglevel {{ p2pool_log_level | int }}
|
||||
{% if sidechain[0] == 1 %}
|
||||
--mini
|
||||
{% endif %}
|
||||
{% if enable_autodiff == False %}
|
||||
--no-autodiff
|
||||
{% endif %}
|
||||
{% if enable_statistics == True %}
|
||||
--local-api
|
||||
--data-api /home/p2pool/.p2pool
|
||||
{% endif %}
|
||||
{% if light_mode == True %}
|
||||
--light-mode
|
||||
{% endif %}
|
||||
{% if no_cache == True %}
|
||||
--no-cache
|
||||
{% endif %}
|
||||
{% if rpc_login != "" %}
|
||||
--rpc-login {{ rpc_login }}
|
||||
{% endif %}
|
||||
{% if p2pool_options != "" %}
|
||||
{{ p2pool_options }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if enable_statistics == True %}
|
||||
statistics:
|
||||
image: statistics:latest
|
||||
build:
|
||||
context: statistics
|
||||
container_name: p2pool-statistics
|
||||
networks:
|
||||
- p2pool
|
||||
ports:
|
||||
- {{ statistics_port }}:80/tcp
|
||||
volumes:
|
||||
- p2pool:/data:r
|
||||
depends_on:
|
||||
- p2pool
|
||||
restart: unless-stopped
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if configure_monero == True %}
|
||||
monero:
|
||||
image: monero:latest
|
||||
build:
|
||||
context: monero
|
||||
args:
|
||||
- MONERO_GIT_TAG={{ monero_version }}
|
||||
container_name: p2pool-monero
|
||||
networks:
|
||||
- p2pool
|
||||
ports:
|
||||
- 18080:18080/tcp
|
||||
{% if expose_rpc_port == True %}
|
||||
- {{ rpc_port }}:18081/tcp
|
||||
{% endif %}
|
||||
volumes:
|
||||
- monero:/home/monero/.bitmonero:rw
|
||||
- /dev/null:/home/monero/.bitmonero/bitmonero.log:rw
|
||||
- /dev/hugepages:/dev/hugepages:rw
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-z", "localhost", "18081"]
|
||||
interval: 2s
|
||||
timeout: 1s
|
||||
start_period: 10s
|
||||
command: >-
|
||||
--zmq-pub tcp://0.0.0.0:18083
|
||||
--disable-dns-checkpoints
|
||||
--enable-dns-blocklist
|
||||
--non-interactive
|
||||
--p2p-bind-ip=0.0.0.0
|
||||
--p2p-bind-port=18080
|
||||
--rpc-bind-ip=0.0.0.0
|
||||
--rpc-bind-port=18081
|
||||
--restricted-rpc
|
||||
--confirm-external-bind
|
||||
--log-level={{ monero_log_level | int }}
|
||||
{% if prune_blockchain == True %}
|
||||
--prune-blockchain
|
||||
{% if sync_pruned_blocks == True %}
|
||||
--sync-pruned-blocks
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if rpc_login != "" %}
|
||||
--rpc-login {{ rpc_login }}
|
||||
{% endif %}
|
||||
{% if limit_data_rates == True %}
|
||||
--limit-rate-up {{ rate_limit_up }}
|
||||
--limit-rate-down {{ rate_limit_down }}
|
||||
{% endif %}
|
||||
{% if fast_sync == True %}
|
||||
--fast-block-sync=1
|
||||
{% else %}
|
||||
--fast-block-sync=0
|
||||
{% endif %}
|
||||
{% if monero_options != "" %}
|
||||
{{ monero_options }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if configure_xmrig == True %}
|
||||
xmrig:
|
||||
image: xmrig:latest
|
||||
build: xmrig
|
||||
container_name: p2pool-xmrig
|
||||
networks:
|
||||
- p2pool
|
||||
privileged: true
|
||||
volumes:
|
||||
- /dev:/dev:ro
|
||||
- /lib/modules:/lib/modules:ro
|
||||
- /dev/hugepages:/dev/hugepages:rw
|
||||
depends_on:
|
||||
- p2pool
|
||||
restart: unless-stopped
|
||||
command: >-
|
||||
--randomx-1gb-pages
|
||||
-o p2pool:3333
|
||||
{% if enable_autodiff == False and use_fixed_difficulty == True %}
|
||||
-u {{ xmrig_username }}+{{ fixed_difficulty | int }}
|
||||
{% else %}
|
||||
-u {{ xmrig_username }}
|
||||
{% endif %}
|
||||
--cpu-max-threads-hint={{ cpu_percent | int }}
|
||||
--cpu-priority={{ cpu_priority | int }}
|
||||
{% if xmrig_options != "" %}
|
||||
{{ xmrig_options }}
|
||||
{% endif %}
|
||||
{% endif %}
|
@ -0,0 +1,3 @@
|
||||
npyscreen==4.10.5
|
||||
MarkupSafe==2.0.1
|
||||
jinja2==2.11.3
|
@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Verifying Requirements:"
|
||||
DOCKER_VER=$(docker version -f "{{.Server.Version}}" 2> /dev/null)
|
||||
if [ -z "$DOCKER_VER" ]; then
|
||||
echo "Docker not found; install it: https://docs.docker.com/engine/install/"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(echo "$DOCKER_VER"| cut -d'.' -f 1)" -ge 19 ] && \
|
||||
[ "$(echo "$DOCKER_VER"| cut -d'.' -f 2)" -ge 0 ] && \
|
||||
[ "$(echo "$DOCKER_VER"| cut -d'.' -f 3)" -ge 3 ]; then
|
||||
echo "Docker Found; OK"
|
||||
else
|
||||
echo "Docker version less than 19.0.3; upgrade it: https://docs.docker.com/engine/install/"
|
||||
exit 1
|
||||
fi
|
||||
docker compose version 2>&1 > /dev/null
|
||||
COMPOSE_PLUGIN_RC=$?
|
||||
docker-compose --version 2>&1 > /dev/null
|
||||
COMPOSE_CLI_RC=$?
|
||||
if [ "$COMPOSE_PLUGIN_RC" -eq 0 ] || [ "$COMPOSE_CLI_RC" -eq 0 ]; then
|
||||
echo "Docker Compose found; OK"
|
||||
if [ "$COMPOSE_PLUGIN_RC" -eq 0 ]; then
|
||||
COMPOSE_COMMAND="docker compose"
|
||||
else
|
||||
COMPOSE_COMMAND="docker-compose"
|
||||
fi
|
||||
else
|
||||
echo "Docker Compose not found; install it: https://docs.docker.com/compose/install/compose-plugin/"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Building and Running P2Pool docker-compose Configuration"
|
||||
docker build -t p2pool_config:latest cfg
|
||||
docker run -it --rm -v $PWD:/docker-compose --user $(id -u):$(id -g) p2pool_config:latest
|
||||
CONFIGURE_RC=$?
|
||||
echo ""
|
||||
echo ""
|
||||
if [ "$CONFIGURE_RC" -eq 0 ]; then
|
||||
echo "P2Pool is configured. Start the project with: $COMPOSE_COMMAND up --build -d"
|
||||
else
|
||||
exit 1
|
||||
fi
|
@ -0,0 +1,37 @@
|
||||
{
|
||||
"wallet_address": "44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg",
|
||||
"configure_monero": true,
|
||||
"configure_xmrig": true,
|
||||
"sidechain": [
|
||||
0
|
||||
],
|
||||
"enable_statistics": true,
|
||||
"statistics_port": "3380",
|
||||
"expose_stratum_port": false,
|
||||
"stratum_port": "3333",
|
||||
"p2pool_log_level": 3,
|
||||
"enable_autodiff": true,
|
||||
"light_mode": false,
|
||||
"no_cache": false,
|
||||
"p2pool_options": "",
|
||||
"monero_version": "latest",
|
||||
"prune_blockchain": true,
|
||||
"monero_log_level": 0,
|
||||
"expose_rpc_port": false,
|
||||
"rpc_port": "18081",
|
||||
"rpc_login": "",
|
||||
"limit_data_rates": false,
|
||||
"rate_limit_up": "2048",
|
||||
"rate_limit_down": "8192",
|
||||
"sync_pruned_blocks": false,
|
||||
"fast_sync": false,
|
||||
"monero_options": "",
|
||||
"public_monero_node": "",
|
||||
"monero_node_login": "",
|
||||
"xmrig_username": "p2pool",
|
||||
"use_fixed_difficulty": true,
|
||||
"fixed_difficulty": 500000,
|
||||
"cpu_percent": 100,
|
||||
"cpu_priority": 2,
|
||||
"xmrig_options": ""
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
FROM python:slim
|
||||
|
||||
COPY app /app
|
||||
|
||||
WORKDIR /app
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
CMD ["/app/p2pool_statistics.py"]
|
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
from datetime import datetime
|
||||
from prefixed import Float
|
||||
import humanfriendly
|
||||
from flask import Flask, render_template
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
##
|
||||
# Add some custom jinja filters
|
||||
def timeago(value):
|
||||
"""Format a date time to human friendly time ago"""
|
||||
if value is None:
|
||||
return ""
|
||||
if type(value) is int:
|
||||
dt = datetime.fromtimestamp(value).replace(microsecond=0)
|
||||
now = datetime.now().replace(microsecond=0)
|
||||
return humanfriendly.format_timespan(now - dt)
|
||||
|
||||
|
||||
app.jinja_env.filters["timeago"] = timeago
|
||||
|
||||
|
||||
def human_numbers(value):
|
||||
"""Format a number in human readable format"""
|
||||
if value is None:
|
||||
return ""
|
||||
return "{:!.3h}".format(Float(value))
|
||||
|
||||
|
||||
app.jinja_env.filters["humanize"] = human_numbers
|
||||
|
||||
|
||||
##
|
||||
# Get Pool Instance Birth Date
|
||||
def birthdate():
|
||||
try:
|
||||
with open("/data/p2pool.blocks") as reader:
|
||||
first_block = reader.readline().rstrip()
|
||||
bday_ts = int(first_block.split(" ")[0])
|
||||
bday = timeago(bday_ts)
|
||||
return bday
|
||||
except Exception as e:
|
||||
return "unknown time"
|
||||
|
||||
|
||||
##
|
||||
# The App Routes
|
||||
@app.route("/")
|
||||
def render():
|
||||
try:
|
||||
my_bday = birthdate()
|
||||
with open("/data/stats_mod", "r") as reader:
|
||||
stats_mod = json.loads(reader.read())
|
||||
with open("/data/pool/stats", "r") as reader:
|
||||
pool_stats = json.loads(reader.read())
|
||||
with open("/data/network/stats", "r") as reader:
|
||||
network_stats = json.loads(reader.read())
|
||||
with open("/data/local/stats", "r") as reader:
|
||||
local_stats = json.loads(reader.read())
|
||||
return render_template(
|
||||
"index.html",
|
||||
my_bday=my_bday,
|
||||
stats_mod=stats_mod,
|
||||
pool_stats=pool_stats,
|
||||
network_stats=network_stats,
|
||||
local_stats=local_stats,
|
||||
)
|
||||
except Exception as e:
|
||||
return render_template("oops.html", error=str(e))
|
||||
|
||||
|
||||
##
|
||||
# main()
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=False, host="0.0.0.0", port=80)
|
@ -0,0 +1,3 @@
|
||||
flask
|
||||
prefixed
|
||||
humanfriendly
|
After Width: | Height: | Size: 5.6 KiB |
@ -0,0 +1,171 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
|
||||
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
|
||||
crossorigin="anonymous">
|
||||
<title>Monero P2Pool Server Statistics</title>
|
||||
</head>
|
||||
<body style="font-size:85%;">
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
|
||||
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
|
||||
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
|
||||
|
||||
<div style="text-align:center;">
|
||||
<img src="{{url_for('static', filename='monero-symbol-480.png')}}" width="75px" height="75px" alt="Monero"/>
|
||||
<h1 style="color: #FFA500;">P2Pool Server Statistics</h1>
|
||||
</div>
|
||||
|
||||
<div class="card-group">
|
||||
<div class="col-sm-4 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-header text-black mb-1 pb-1" style="background-color: #FFA500;"><h2>Local Pool</h2></div>
|
||||
<div class="card-body mb-0 pb-0">
|
||||
<h6 class="card-subtitle text-muted" style="font-size:80%;">(note: stats reset on restart)</h6>
|
||||
<div class="table-responsive table-hover table-condensed table-striped">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Hashrate 15 Minutes</td>
|
||||
<td>{{ local_stats["hashrate_15m"]|humanize }}H/s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Hashrate 1 Hour</td>
|
||||
<td>{{ local_stats["hashrate_1h"]|humanize }}H/s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Hashrate 24 Hours</td>
|
||||
<td>{{ local_stats["hashrate_24h"]|humanize }}H/s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current Effort</td>
|
||||
<td>{{ local_stats["current_effort"] }}%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Miner Connections</td>
|
||||
<td>{{ local_stats["incoming_connections"] }}<td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Hashes</td>
|
||||
<td>{{ local_stats["total_hashes"]|humanize }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shares Found</td>
|
||||
<td>{{ local_stats["shares_found"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Average Effort</td>
|
||||
<td>{{ local_stats["average_effort"] }}%</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-header text-black mb-1 pb-1" style="background-color: #FFA500;"><h2>Global Pool</h2></div>
|
||||
<div class="card-body mb-0 pb-0">
|
||||
<h6 class="card-subtitle text-muted" style="font-size:80%;"> </h6>
|
||||
<div class="table-responsive table-hover table-condensed table-striped">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Hash Rate</td>
|
||||
<td>{{ pool_stats["pool_statistics"]["hashRate"]|humanize }}H/s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Round Hashes</td>
|
||||
<td>{{ stats_mod["pool"]["roundHashes"]|humanize }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last Block Found</td>
|
||||
<td>{{ pool_stats["pool_statistics"]["lastBlockFound"] }} <br>
|
||||
{{ pool_stats["pool_statistics"]["lastBlockFoundTime"]|timeago }} ago</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Payout Method</td>
|
||||
<td>{{ pool_stats["pool_list"]|join(',') }}<br>2160 block window (~6 hours)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h6 class="card-subtitle text-muted" style="font-size:80%;">(since instance birth: {{ my_bday }} ago)</h6>
|
||||
<div class="table-responsive table-hover table-condensed table-striped">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total Hashes</td>
|
||||
<td>{{ pool_stats["pool_statistics"]["totalHashes"]|humanize }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Blocks Found</td>
|
||||
<td>{{ pool_stats["pool_statistics"]["totalBlocksFound"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Known Miners</td>
|
||||
<td>{{ pool_stats["pool_statistics"]["miners"] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-header text-black mb-1 pb-1" style="background-color: #FFA500;"><h2>Monero Network</h2></div>
|
||||
<div class="card-body mb-0 pb-0">
|
||||
<h6 class="card-subtitle text-muted" style="font-size:80%;"> </h6>
|
||||
<div class="table-responsive table-hover table-condensed table-striped">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Height</td>
|
||||
<td>{{ network_stats["height"] }}<br>
|
||||
{{ network_stats["timestamp"]|timeago }} ago</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Difficulty</td>
|
||||
<td>{{ network_stats["difficulty"]|humanize }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Reward</td>
|
||||
<td>0.{{ network_stats["reward"] }} Monero</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Head Hash</td>
|
||||
<td>{{ network_stats["hash"] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.setInterval('refresh()', 30000); // Call refresh function every 30000 milliseconds (30 seconds).
|
||||
function refresh() {
|
||||
window .location.reload();
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Oops</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Ooops, something went wrong:</h2>
|
||||
{{ error }}
|
||||
(Maybe you need to wait a few minutes for p2pool to start and sync for the first time?)
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
||||
Subproject commit 7167cf1ce6e5e9b240967e0d96148966a24bbdb0
|
||||
Subproject commit 256d27c5c5a8c9f22b9711b71b24f1978fdb66cc
|
@ -1 +1 @@
|
||||
Subproject commit 26362337a9bf3c3e7e7887338fa35b596a2bae59
|
||||
Subproject commit 7742eb369387b3c7caba8483f1dd7e8d89915042
|
@ -1 +1 @@
|
||||
Subproject commit 2bd75e5686b2e6ff3824c4dfb2b6ec86b60f454c
|
||||
Subproject commit e5926fe5f91ae5673c7d5e31e484aed4188581f7
|
@ -1 +1 @@
|
||||
Subproject commit 99ab53e9980dc0b2fb31b4615ce754bf1f35826f
|
||||
Subproject commit 1a91b51976a1adc6972081faa78b6b70022254d3
|
Loading…
Reference in new issue