diff --git a/README.md b/README.md index c44062f7..8ba0b17f 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,14 @@ Enter you Wallet Address in the input tab when you start up the dashboard ## UI Operation ``` -docker compose build # builds the latest docker image +# USING LATEST DOCKER IMAGE FROM GIT +docker compose pull # pulls the latest docker image docker compose up -d # Runs the UI docker compose down # Stops the UI + +# ALTERNATIVELY YOU CAN BUILD IT YOURSELF +git pull # ensure you have latest files from git +docker compose up --build ``` In a web browser you can navigate to: http://localhost:8050/ diff --git a/conf/conf.yaml b/conf/conf.yaml index e2a4aef5..b92780d1 100644 --- a/conf/conf.yaml +++ b/conf/conf.yaml @@ -8,6 +8,7 @@ default_values: url: 'https://api.ergo.aap.cornell.edu/api/v1/boxes/unspent/byAddress/' token_ls: 'https://api.ergo.aap.cornell.edu/api/v1/tokens' base_api: 'http://15.204.211.130:4000/api/pools/ErgoSigmanauts' + db_name: 'db' stats_cols: [ 'fee NUMERIC', # Numeric type for precision 'paid NUMERIC', # Numeric type for decimal values diff --git a/docker-compose-Copy1.yaml b/docker-compose-Copy1.yaml deleted file mode 100644 index 283d1d7b..00000000 --- a/docker-compose-Copy1.yaml +++ /dev/null @@ -1,36 +0,0 @@ -version: '3.8' - -services: - db: - image: postgres:latest - environment: - POSTGRES_DB: mining-db - POSTGRES_USER: marctheshark - POSTGRES_PASSWORD: password - volumes: - - mining_data:/var/lib/postgresql/data - restart: unless-stopped - ports: - - "5431:5432" - - app: - build: - context: . - volumes: - - ./:/app - ports: - - "8050:8050" - restart: unless-stopped - depends_on: - - db - - pool-ui: - image: ghcr.io/marctheshark3/sigmanaut-mining-pool-ui:main - ports: - - "8050:8050" - restart: unless-stopped - depends_on: - - db - -volumes: - mining_data: diff --git a/docker-compose-diy.yaml b/docker-compose-diy.yaml deleted file mode 100644 index 79bbe5a1..00000000 --- a/docker-compose-diy.yaml +++ /dev/null @@ -1,29 +0,0 @@ -version: '3.8' - -services: - db: - image: postgres:latest - environment: - POSTGRES_DB: mining-db - POSTGRES_USER: marctheshark - POSTGRES_PASSWORD: password - volumes: - - mining_data:/var/lib/postgresql/data - restart: unless-stopped - ports: - - "5431:5432" - - app: - build: - context: . - dockerfile: Dockerfile # Make sure this is the name of your Dockerfile - volumes: - - ./:/app - ports: - - "8050:8050" - restart: unless-stopped - depends_on: - - db - -volumes: - mining_data: diff --git a/docker-compose.yaml b/docker-compose.yaml index 79bbe5a1..24b0ad92 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -14,9 +14,10 @@ services: - "5431:5432" app: + image: ghcr.io/marctheshark3/sigmanaut-mining-pool-ui:main build: context: . - dockerfile: Dockerfile # Make sure this is the name of your Dockerfile + dockerfile: Dockerfile volumes: - ./:/app ports: diff --git a/layouts/mining_page.py b/layouts/mining_page.py index 6fa35b88..ec72eaf3 100644 --- a/layouts/mining_page.py +++ b/layouts/mining_page.py @@ -50,15 +50,8 @@ def update_front_row(n, pathname): total_df = worker_df[worker_df.worker == 'totals'] my_worker_df = total_df[total_df.miner == miner] latest_worker = my_worker_df[my_worker_df.created == max(my_worker_df.created)] - # try: + my_total_hash = latest_worker.hashrate.item() - # except ValueError: - # timenow = pd.Timestamp.now() - # db_sync.update_miner_data(timenow=timenow, payment=False, live_data=True, performance=False) - # worker_df = db_sync.db.fetch_data('live_worker') - # total_df = worker_df[worker_df.worker == 'totals'] - # my_worker_df = total_df[total_df.miner == miner] - # my_total_hash = my_worker_df.hashrate.item() my_effort = latest_worker.effort.item() my_ttf = latest_worker.ttf.item() @@ -165,33 +158,70 @@ def update_outside(n, pathname): return [payment_children] - @app.callback([Output('chart', 'figure'),], - [Input('mp-interval-2', 'n_intervals')], + @app.callback([Output('chart', 'figure'),Output('chart-title', 'children'),], + [Input('mp-interval-2', 'n_intervals'), + Input('chart-dropdown', 'value')], [State('url', 'pathname')]) - def update_charts(n_intervals, pathname): + def update_charts(n_intervals, chart, pathname): wallet = unquote(pathname.lstrip('/')) - df = db_sync.db.fetch_data('performance') - my_worker_performance = df[df.miner == wallet] - my_worker_performance= my_worker_performance.sort_values('created') - - miner_performance_chart = px.line(my_worker_performance, - x='created', - y='hashrate', - color='worker', - labels={'hashrate': 'Hashrate', 'created': 'Time'}, - markers=True) - - miner_performance_chart.update_layout( - paper_bgcolor='rgba(0,0,0,0)', - plot_bgcolor='rgba(0,0,0,0)', - legend_title_text='Miner', - legend=dict(font=dict(color='#FFFFFF')), - titlefont=dict(color='#FFFFFF'), - xaxis=dict(title='Time', color='#FFFFFF',showgrid=False, showline=False, zeroline=False), - yaxis=dict(title='Hashrate', color='#FFFFFF') - ) - return [miner_performance_chart] + + if chart == 'workers': + df = db_sync.db.fetch_data('performance') + my_worker_performance = df[df.miner == wallet] + my_worker_performance= my_worker_performance.sort_values('created') + + miner_performance_chart = px.line(my_worker_performance, + x='created', + y='hashrate', + color='worker', + labels={'hashrate': 'Hashrate', 'created': 'Time'}, + markers=True) + + miner_performance_chart.update_layout( + paper_bgcolor='rgba(0,0,0,0)', + plot_bgcolor='rgba(0,0,0,0)', + legend_title_text='Miner', + legend=dict(font=dict(color='#FFFFFF')), + titlefont=dict(color='#FFFFFF'), + xaxis=dict(title='Time', color='#FFFFFF',showgrid=False, showline=False, zeroline=False), + yaxis=dict(title='Hashrate', color='#FFFFFF') + ) + return [miner_performance_chart, 'WORKER HASHRATE OVER TIME'] + + elif chart == 'payments': + df = db_sync.db.fetch_data('payment') + df = df[df.miner == wallet] + dates = df.lastpayment.unique() # get all of the payment dates + + ls = [] + for date in dates: + temp = df[df.lastpayment == date] + temp = temp[temp.created_at == max(temp.created_at)] # filter by the latest payment stamp + ls.append(temp) + + df = pd.concat(ls) + + df = df.sort_values('lastpayment') + + payment_chart = px.line(df, + x='lastpayment', + y='todaypaid', + # color='todaypaid', + labels={'todaypaid': 'Paid [ERG]', 'lastpayment': 'Date'}, + markers=True) + + payment_chart.update_layout( + paper_bgcolor='rgba(0,0,0,0)', + plot_bgcolor='rgba(0,0,0,0)', + # legend_title_text='Miner', + legend=dict(font=dict(color='#FFFFFF')), + titlefont=dict(color='#FFFFFF'), + xaxis=dict(title='Date', color='#FFFFFF',showgrid=False, showline=False, zeroline=False), + yaxis=dict(title='Paid [ERG]', color='#FFFFFF') + ) + return [payment_chart, 'PAYMENT OVER TIME'] + @@ -255,7 +285,38 @@ def get_layout(reader): dbc.Col(md=md, style={'padding': '7px'}, children=[dbc.Card(style=bottom_row_style, id='s3')],)]), - html.H2('Worker Hashrate Over Time', style={'color': 'white', 'textAlign': 'center',}), + # html.H2('Worker Hashrate Over Time', style={'color': 'white', 'textAlign': 'center',}), + + html.Div( + [ + html.Div( + html.H1( + id='chart-title', + children='Please select an option', + style={'fontSize': '24px'} + ), + style={'flex': '1'} + ), + html.Div( + dcc.Dropdown( + id='chart-dropdown', + options=[ + {'label': 'Worker Hashrate Over Time', 'value': 'workers'}, + {'label': 'Payment Over Time', 'value': 'payments'} + ], + value='workers', # Default value + style={'width': '300px', 'color': 'black'} + ), + style={'flex': '1'} + ) + ], + style={ + 'display': 'flex', + 'justifyContent': 'space-between', + 'alignItems': 'center', + 'padding': '10px' + } + ), dcc.Graph(id='chart', style={'backgroundColor': card_color, 'padding': '20px'}), html.Div( diff --git a/testing_2_db.ipynb b/testing_2_db.ipynb index a6416ea0..1a230fbc 100644 --- a/testing_2_db.ipynb +++ b/testing_2_db.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 3, "id": "96944386-e139-4ef4-9d86-26463244ff6f", "metadata": {}, "outputs": [], @@ -17,30 +17,19 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 8, "id": "11604c9d-4ef6-48da-939f-fac113478414", "metadata": {}, "outputs": [], "source": [ - "db_sync = DataSyncer(config_path=\"../conf\")\n", + "db_name = 'localhost'\n", + "db_sync = DataSyncer(config_path=\"../conf\", db_name=db_name)\n", "miner = '9ehJZvPDgvCNNd2zTQHxnSpcCAtb1kHbEN1VAgeoRD5DPVApYkk'" ] }, { "cell_type": "code", - "execution_count": null, - "id": "4994b7a3-98ce-48ba-9635-3850b2a6f9fd", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "db_sync.__delete_table__()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "id": "7fd703d1-62a2-4def-a041-09dad714ab9e", "metadata": { "scrolled": true @@ -51,7 +40,6 @@ "output_type": "stream", "text": [ "intializing DB\n", - "Batch 1/1: Deleted up to 100 rows from stats\n", "UPDATED STATS TABLE SUCCESFULLY\n", "UPDATED BLOCK TABLE SUCCESFULLY\n" ] @@ -75,107 +63,250 @@ " 'connectedpeers', 'rewardtype', 'pooleffort', 'poolttf', 'price',\n", " 'insert_time_stamp'],\n", " dtype='object')\n", - "no live data for miner 9fGzn8VCszvFMXo2KDrQiVowwSdchVT13ygX26RKUfkjcruRq7J\n", - "no live data for miner 9gHULKUh8kLBBc6F6ddtyzeyhzz2KzGerPbFw7ZHmSUPrRGfnoz\n", + "no live data for miner 9eZVqXVnrVWQKK19b7E7kp4ZyNqanp2z1mpKUJRaouNsmeFsakQ\n", + "no live data for miner 9h4Q7d8b98Pr77CVd99n5gcWi6tz4MtkyGRFFkh2FQDYfWYt1mP\n", + "no live data for miner 9hyzuf6zUyWR2z3vTBCkwXNceCE3WuVVhVLMzEDUsdu5rqHq525\n", + "no live data for miner 9h1B5mgnHMpLtJfSxuBkgiD2GUYUKbuoYw5pokhhEdJxtJMLrM6\n", + "no live data for miner 9gyKCPYkaBJp7z8NxxCygjwB6u9GLudiakUEUPpZ1bjhbJUip8z\n", + "no live data for miner 9gcwns63b8GJkZtu2j655xQRtAdYjy6SKdjNkMNRjYj7Git9HxP\n", "UPDATED LIVE WORK, PERFORMANCE, AND PAYMENT TABLES SUCCESFULLY\n", "complete\n" ] } ], "source": [ - "init_db()" + "init_db('localhost')" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "b1a091c8-8c73-4dcf-b74d-26832707cae3", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "UPDATED STATS TABLE SUCCESFULLY\n" + ] + } + ], "source": [ - "update_pool_stats()" + "update_pool_stats(db_name)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "b586b668-4840-46f4-b2c6-d169ecf87f16", "metadata": {}, - "outputs": [], - "source": [ - "update_blocks_and_live_workers()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4bae6d28-ddd3-4b9e-9d34-34eeff29e80b", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "df = db_sync.db.fetch_data('performance')\n", - "df = df[df.miner == miner]\n", - "df = df[df.worker == 'GRAYSPEAK']\n", - "df[df.created == '2024-05-06 16:00:00']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "419e47a1-3e7f-4636-8735-415e9d483ad1", - "metadata": {}, - "outputs": [], - "source": [ - "worker_df = db_sync.db.fetch_data('live_worker')\n", - "total_df = worker_df[worker_df.worker == 'totals']\n", - "my_worker_df = total_df[total_df.miner == miner]\n", - "latest_worker = my_worker_df[my_worker_df.created == max(my_worker_df.created)]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "426a7e20-dc50-4ee0-aa96-b0cb419058f2", - "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "UPDATED BLOCK TABLE SUCCESFULLY\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/whaleshark/Documents/sigmanaut-mining-pool-ui/utils/db_util.py:222: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n", + " return pd.read_sql_query(query, self.conn)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Index(['fee', 'paid', 'blocks', 'last_block_found', 'enabled',\n", + " 'minimumpayment', 'payoutscheme', 'connectedminers', 'poolhashrate',\n", + " 'sharespersecond', 'networktype', 'networkhashrate',\n", + " 'networkdifficulty', 'lastnetworkblocktime', 'blockheight',\n", + " 'connectedpeers', 'rewardtype', 'pooleffort', 'poolttf', 'price',\n", + " 'insert_time_stamp'],\n", + " dtype='object')\n", + "no live data for miner 9eZVqXVnrVWQKK19b7E7kp4ZyNqanp2z1mpKUJRaouNsmeFsakQ\n", + "no live data for miner 9h4Q7d8b98Pr77CVd99n5gcWi6tz4MtkyGRFFkh2FQDYfWYt1mP\n", + "no live data for miner 9hyzuf6zUyWR2z3vTBCkwXNceCE3WuVVhVLMzEDUsdu5rqHq525\n", + "no live data for miner 9h1B5mgnHMpLtJfSxuBkgiD2GUYUKbuoYw5pokhhEdJxtJMLrM6\n", + "no live data for miner 9gyKCPYkaBJp7z8NxxCygjwB6u9GLudiakUEUPpZ1bjhbJUip8z\n", + "no live data for miner 9gcwns63b8GJkZtu2j655xQRtAdYjy6SKdjNkMNRjYj7Git9HxP\n", + "UPDATED LIVE WORK, PERFORMANCE, AND PAYMENT TABLES SUCCESFULLY\n" + ] + } + ], "source": [ - "my_total_hash = latest_worker.hashrate.item()\n", - "my_total_hash" + "update_blocks_and_live_workers(db_name)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "92e7468a-4474-45cc-8b02-a12bcb93aa3c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/whaleshark/Documents/sigmanaut-mining-pool-ui/utils/db_util.py:222: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n", + " return pd.read_sql_query(query, self.conn)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Index(['fee', 'paid', 'blocks', 'last_block_found', 'enabled',\n", + " 'minimumpayment', 'payoutscheme', 'connectedminers', 'poolhashrate',\n", + " 'sharespersecond', 'networktype', 'networkhashrate',\n", + " 'networkdifficulty', 'lastnetworkblocktime', 'blockheight',\n", + " 'connectedpeers', 'rewardtype', 'pooleffort', 'poolttf', 'price',\n", + " 'insert_time_stamp'],\n", + " dtype='object')\n", + "UPDATED LIVE WORK, PERFORMANCE, AND PAYMENT TABLES SUCCESFULLY\n" + ] + } + ], "source": [ - "update_payment_and_performance()" + "update_payment_and_performance(db_name)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "729c6b38-f34e-454d-9325-630be159eb62", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "UPDATED STATS TABLE SUCCESFULLY\n" + ] + } + ], "source": [ - "update_pool_stats()" + "update_pool_stats(db_name)" ] }, { "cell_type": "code", - "execution_count": null, - "id": "dca3cb9d-d4de-411b-8832-5dd41d582542", + "execution_count": 16, + "id": "0fa8be8d-6170-4b05-8ea6-ac30c582a983", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/whaleshark/Documents/sigmanaut-mining-pool-ui/utils/db_util.py:222: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n", + " return pd.read_sql_query(query, self.conn)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + " | pendingshares | \n", + "pendingbalance | \n", + "totalpaid | \n", + "todaypaid | \n", + "schema | \n", + "price | \n", + "lastpayment | \n", + "lastpaymentlink | \n", + "created_at | \n", + "miner | \n", + "
---|---|---|---|---|---|---|---|---|---|---|
990 | \n", + "98.33 | \n", + "0.0 | \n", + "338.45 | \n", + "1.464749 | \n", + "PPLNS | \n", + "1.18 | \n", + "2024-05-08 | \n", + "https://explorer.ergoplatform.com/en/transacti... | \n", + "2024-05-08 11:56:01.671197 | \n", + "9ehJZvPDgvCNNd2zTQHxnSpcCAtb1kHbEN1VAgeoRD5DPV... | \n", + "
1201 | \n", + "65.20 | \n", + "0.0 | \n", + "342.52 | \n", + "2.661853 | \n", + "PPLNS | \n", + "1.26 | \n", + "2024-05-09 | \n", + "https://explorer.ergoplatform.com/en/transacti... | \n", + "2024-05-09 09:40:07.269795 | \n", + "9ehJZvPDgvCNNd2zTQHxnSpcCAtb1kHbEN1VAgeoRD5DPV... | \n", + "