Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
81f6a0b
Add scoreboard API
mutatrum Sep 16, 2025
6306d8c
Add scoreboard page
mutatrum Sep 16, 2025
2e56135
Fix difficultyPipe for M and greater
mutatrum Sep 16, 2025
fa4eaef
Print NVS stats at startup
mutatrum Sep 16, 2025
7ad71e1
Add persistent scoreboard
mutatrum Sep 16, 2025
8f8763b
Remove superfluous mutex create
mutatrum Sep 16, 2025
600f056
Remove newline
mutatrum Sep 16, 2025
b7f7ada
Hook scoreboard on destroy
mutatrum Sep 16, 2025
ef1a842
Remove EOF newlines
mutatrum Sep 16, 2025
587c15f
Remove changes from #1237
mutatrum Sep 17, 2025
9090b12
Unified suffix pipes
mutatrum Sep 17, 2025
7fd1159
Add loader
Sep 17, 2025
290f5ce
Add documentation
mutatrum Sep 17, 2025
19f8604
Wrong type
mutatrum Sep 17, 2025
ac00030
Table styling
Sep 17, 2025
b8b0b85
Merge pull request #4 from duckaxe/cr/mutatrum/1236-1
mutatrum Sep 17, 2025
ea90af1
Add sorting and tooltips
mutatrum Sep 18, 2025
80b7c91
Add EOF newline
mutatrum Sep 18, 2025
121e974
Clean up scoreboard styling
mutatrum Sep 19, 2025
df0311e
Limit dateAgo on scoreboard / Make dateAgo less jumpy
mutatrum Sep 19, 2025
011f3fc
Fix table column width
Sep 19, 2025
f1f3fd6
text-center fix
mutatrum Sep 19, 2025
de917fc
Revert text-center
mutatrum Sep 19, 2025
0c42c54
Merge branch 'master' of https://github.com/bitaxeorg/ESP-Miner into …
mutatrum Sep 19, 2025
5297728
Replace ByteSuffixPipe with SuffixPipe
mutatrum Sep 19, 2025
2749eba
Merge pull request #5 from duckaxe/cr/mutatrum/1236-5
mutatrum Sep 20, 2025
0f4a7ab
Fix table column min-width
Sep 21, 2025
c86b77a
Merge branch 'master' of https://github.com/bitaxeorg/ESP-Miner into …
mutatrum Sep 21, 2025
0a29a5f
Catch xTaskCreate errors
mutatrum Sep 22, 2025
5bbe117
Merge branch 'master' of https://github.com/bitaxeorg/ESP-Miner into …
mutatrum Sep 22, 2025
7cc5757
Fix tooltip
mutatrum Sep 23, 2025
a170897
Merge branch 'master' into scoreboard
mutatrum Sep 25, 2025
cfb84c8
Merge branch 'master' into scoreboard
mutatrum Oct 2, 2025
ef90eb0
Merge branch 'master' of https://github.com/bitaxeorg/ESP-Miner into …
mutatrum Oct 29, 2025
49ae8ab
Revert unified pipes
mutatrum Oct 29, 2025
4d99382
Add support for indexed NVS keys
mutatrum Oct 29, 2025
5c3eae1
Merge branch 'master' of https://github.com/bitaxeorg/ESP-Miner into …
mutatrum Oct 29, 2025
0d756b5
Merge branch 'scoreboard' of https://github.com/mutatrum/ESP-Miner in…
mutatrum Oct 29, 2025
d7457c5
Remove superfluous changes
mutatrum Oct 29, 2025
0354659
More superfluous changes removed
mutatrum Oct 29, 2025
9ed92ef
Delete .clangd
mutatrum Oct 29, 2025
d6eec66
Remove whitespace
mutatrum Oct 29, 2025
e2653d0
Merge branch 'master' into scoreboard
mutatrum Nov 3, 2025
578bf12
Merge branch 'master' into scoreboard
mutatrum Nov 7, 2025
9e80dcc
Merge branch 'master' into scoreboard
mutatrum Nov 8, 2025
d446af5
Fix merge
mutatrum Nov 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions components/stratum/include/stratum_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ int STRATUM_V1_suggest_difficulty(int socket, int send_uid, uint32_t difficulty)

int STRATUM_V1_extranonce_subscribe(int socket, int send_uid);

int STRATUM_V1_submit_share(int socket, int send_uid, const char *username, const char *jobid,
int STRATUM_V1_submit_share(int socket, int id, const char *username, const char *job_id,
const char *extranonce_2, const uint32_t ntime, const uint32_t nonce,
const uint32_t version);
const uint32_t version_bits);

double STRATUM_V1_get_response_time_ms(int request_id);

Expand Down
12 changes: 7 additions & 5 deletions components/stratum/stratum_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,19 +415,21 @@ int STRATUM_V1_authorize(int socket, int send_uid, const char * username, const
}

/// @param socket Socket to write to
/// @param id Message ID
/// @param username The client’s user name.
/// @param jobid The job ID for the work being submitted.
/// @param ntime The hex-encoded time value use in the block header.
/// @param job_id The job ID for the work being submitted.
/// @param extranonce_2 The hex-encoded value of extra nonce 2.
/// @param ntime The hex-encoded time value use in the block header.
/// @param nonce The hex-encoded nonce value to use in the block header.
int STRATUM_V1_submit_share(int socket, int send_uid, const char * username, const char * jobid,
/// @param version_bits The hex-encoded version bits set by miner (BIP310).
int STRATUM_V1_submit_share(int socket, int id, const char * username, const char * job_id,
const char * extranonce_2, const uint32_t ntime,
const uint32_t nonce, const uint32_t version)
const uint32_t nonce, const uint32_t version_bits)
{
char submit_msg[BUFFER_SIZE];
sprintf(submit_msg,
"{\"id\": %d, \"method\": \"mining.submit\", \"params\": [\"%s\", \"%s\", \"%s\", \"%08lx\", \"%08lx\", \"%08lx\"]}\n",
send_uid, username, jobid, extranonce_2, ntime, nonce, version);
id, username, job_id, extranonce_2, ntime, nonce, version_bits);
debug_stratum_tx(submit_msg);

return write(socket, submit_msg, strlen(submit_msg));
Expand Down
1 change: 1 addition & 0 deletions main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ SRCS
"./tasks/asic_result_task.c"
"./tasks/power_management_task.c"
"./tasks/statistics_task.c"
"./tasks/scoreboard.c"
"./thermal/EMC2101.c"
"./thermal/EMC2103.c"
"./thermal/TMP1075.c"
Expand Down
2 changes: 2 additions & 0 deletions main/global_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "work_queue.h"
#include "device_config.h"
#include "display.h"
#include "scoreboard.h"

#define STRATUM_USER CONFIG_STRATUM_USER
#define FALLBACK_STRATUM_USER CONFIG_FALLBACK_STRATUM_USER
Expand Down Expand Up @@ -72,6 +73,7 @@ typedef struct
char firmware_update_filename[20];
char firmware_update_status[20];
char * asic_status;
Scoreboard scoreboard;
} SystemModule;

typedef struct
Expand Down
6 changes: 6 additions & 0 deletions main/http_server/axe-os/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { UpdateComponent } from './components/update/update.component';
import { SettingsComponent } from './components/settings/settings.component';
import { NetworkComponent } from './components/network/network.component';
import { SwarmComponent } from './components/swarm/swarm.component';
import { ScoreboardComponent } from './components/scoreboard/scoreboard.component';
import { DesignComponent } from './components/design/design.component';
import { PoolComponent } from './components/pool/pool.component';
import { AppLayoutComponent } from './layout/app.layout.component';
Expand Down Expand Up @@ -67,6 +68,11 @@ const routes: Routes = [
component: SwarmComponent,
title: `${TITLE_PREFIX} Swarm`,
},
{
path: 'scoreboard',
component: ScoreboardComponent,
title: `${TITLE_PREFIX} Scoreboard`,
},
{
path: 'design',
component: DesignComponent,
Expand Down
6 changes: 4 additions & 2 deletions main/http_server/axe-os/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ import { UpdateComponent } from './components/update/update.component';
import { NetworkComponent } from './components/network/network.component';
import { SettingsComponent } from './components/settings/settings.component';
import { SwarmComponent } from './components/swarm/swarm.component';
import { ScoreboardComponent } from './components/scoreboard/scoreboard.component';
import { ThemeConfigComponent } from './components/design/theme-config.component';
import { DesignComponent } from './components/design/design.component';
import { AppLayoutModule } from './layout/app.layout.module';
import { ANSIPipe } from './pipes/ansi.pipe';
import { DateAgoPipe } from './pipes/date-ago.pipe';
import { HashSuffixPipe } from './pipes/hash-suffix.pipe';
import { SuffixPipe } from './pipes/suffix.pipe';
import { PrimeNGModule } from './prime-ng.module';
import { MessageModule } from 'primeng/message';
import { TooltipModule } from 'primeng/tooltip';
Expand Down Expand Up @@ -55,8 +56,9 @@ const components = [
ANSIPipe,
DateAgoPipe,
SwarmComponent,
ScoreboardComponent,
SettingsComponent,
HashSuffixPipe,
SuffixPipe,
ThemeConfigComponent,
DesignComponent,
PoolComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<span class="block text-500 font-medium mb-3">Hashrate</span>
<div class="text-900 font-medium text-2xl flex align-items-center gap-2">
<span *ngIf="!info.power_fault">
{{info.hashRate * 1000000000 | hashSuffix}}
{{info.hashRate * 1000000000 | suffix}}H/s
</span>
<span *ngIf="info.power_fault" class="text-red-500">
Not available - Power fault
Expand All @@ -42,12 +42,12 @@
<ng-container *ngIf="!info.power_fault">
Average:
<span class="text-green-500 font-medium">
{{calculateAverage(hashrateData) | hashSuffix}}
{{calculateAverage(hashrateData) | suffix}}H/s
</span>
</ng-container>

<div class="text-500 text-xs" *ngIf="!info.power_fault && info.expectedHashrate">
Expected: {{info.expectedHashrate * 1000000000 | hashSuffix}}
Expected: {{info.expectedHashrate * 1000000000 | suffix}}H/s
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,3 @@
flex-shrink: 0;
}
}

.code {
line-break: anywhere;
font-family: 'Courier New', Courier, monospace;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { interval, map, Observable, shareReplay, startWith, switchMap, tap, first, Subject, takeUntil } from 'rxjs';
import { HashSuffixPipe } from 'src/app/pipes/hash-suffix.pipe';
import { SuffixPipe } from 'src/app/pipes/suffix.pipe';
import { QuicklinkService } from 'src/app/services/quicklink.service';
import { ShareRejectionExplanationService } from 'src/app/services/share-rejection-explanation.service';
import { LoadingService } from 'src/app/services/loading.service';
Expand Down Expand Up @@ -163,7 +163,7 @@ export class HomeComponent implements OnInit, OnDestroy {
if (tooltipItem.dataset.label === 'ASIC Temp') {
label += tooltipItem.raw + ' °C';
} else {
label += HashSuffixPipe.transform(tooltipItem.raw);
label += SuffixPipe.transform(tooltipItem.raw) + 'H/s';
}
return label;
}
Expand All @@ -188,7 +188,7 @@ export class HomeComponent implements OnInit, OnDestroy {
y: {
ticks: {
color: primaryColor,
callback: (value: number) => HashSuffixPipe.transform(value)
callback: (value: number) => SuffixPipe.transform(value) + 'H/s'
},
grid: {
color: surfaceBorder,
Expand Down Expand Up @@ -318,7 +318,7 @@ export class HomeComponent implements OnInit, OnDestroy {
[
this.pageDefaultTitle,
info.hostname,
(info.hashRate ? HashSuffixPipe.transform(info.hashRate * 1000000000) : false),
(info.hashRate ? SuffixPipe.transform(info.hashRate * 1000000000) + 'H/s' : false),
(info.temp ? `${info.temp}${info.temp2 > -1 ? `/${info.temp2}` : ''}${info.vrTemp ? `/${info.vrTemp}` : ''} °C` : false),
(!info.power_fault ? `${info.power} W` : false),
(info.bestDiff ? info.bestDiff : false),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<div class="card" *ngIf="scoreboard$ | async as scoreboard">
<h2>Scoreboard</h2>

<div class="card scoreboard-card">
<table class="scoreboard-table">
<thead>
<tr>
<th>Rank</th>
<th>Difficulty</th>
<th>Job ID</th>
<th>ExtraNonce2</th>
<th>Time</th>
<th>Nonce</th>
<th>Version Bits</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let entry of scoreboard; let i = index">
<td class="trophy-column">
<i class="pi pi-trophy" [ngClass]="{
'gold': i === 0,
'silver': i === 1,
'bronze': i === 2
}" *ngIf="i < 3"></i>
</td>
<td class="font-bold text-900">{{ entry.difficulty | suffix }}</td>
<td class="code">{{ entry.job_id }}</td>
<td class="code">{{ entry.extranonce2 }}</td>
<td>{{ entry.ntime * 1000 | date:'yyyy-MM-dd HH:mm:ss' }}</td>
<td class="code">{{ entry.nonce }}</td>
<td class="code">{{ entry.version_bits }}</td>
</tr>
</tbody>
</table>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.scoreboard-card {
width: 100%;
box-sizing: border-box;
}

.scoreboard-table {
width: 100%;
border-collapse: collapse;
}

.scoreboard-table th,
.scoreboard-table td {
padding: 0.5rem;
text-align: left;
}

.scoreboard-table th {
font-weight: bold;
}

.trophy-column {
width: 50px;
text-align: center;
}

.pi-trophy.gold {
color: #FFD700;
}

.pi-trophy.silver {
color: #C0C0C0;
}

.pi-trophy.bronze {
color: #CD7F32;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ScoreboardComponent } from './scoreboard.component';

describe('SystemComponent', () => {
let component: ScoreboardComponent;
let fixture: ComponentFixture<ScoreboardComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ScoreboardComponent]
})
.compileComponents();

fixture = TestBed.createComponent(ScoreboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Component, OnDestroy } from '@angular/core';
import { Observable, Subject, switchMap, shareReplay, timer, takeUntil } from 'rxjs';
import { SystemService } from 'src/app/services/system.service';
import { ISystemScoreboardEntry } from 'src/models/ISystemScoreboard';

@Component({
selector: 'app-scoreboard',
templateUrl: './scoreboard.component.html',
styleUrls: ['./scoreboard.component.scss']
})
export class ScoreboardComponent implements OnDestroy {
public scoreboard$: Observable<ISystemScoreboardEntry[]>;

private destroy$ = new Subject<void>();

constructor(
private systemService: SystemService,
) {
this.scoreboard$ = timer(0, 5000).pipe(
switchMap(() => this.systemService.getScoreboard()),
shareReplay({refCount: true, bufferSize: 1}),
takeUntil(this.destroy$)
);
}

ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
},
{
label: 'Total Hashrate',
value: totals.hashRate * 1000000000 | hashSuffix
value: (totals.hashRate * 1000000000 | suffix) + 'H/s'
},
{
label: 'Total Power',
Expand Down Expand Up @@ -128,7 +128,7 @@
tooltipPosition="top">{{axe.IP}}</a>
</td>
<td>{{axe.hostname}}</td>
<td>{{axe.hashRate * 1000000000 | hashSuffix}}</td>
<td>{{axe.hashRate * 1000000000 | suffix}}H/s</td>
<td>
<div class="w-min cursor-pointer"
pTooltip="Shares Accepted"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class AppMenuComponent implements OnInit {
label: 'Menu',
items: [
{ label: 'Dashboard', icon: 'pi pi-fw pi-home', routerLink: ['/'] },
{ label: 'Scoreboard', icon: 'pi pi-fw pi-trophy', routerLink: ['scoreboard'] },
{ label: 'Swarm', icon: 'pi pi-fw pi-sitemap', routerLink: ['swarm'] },
{ label: 'Logs', icon: 'pi pi-fw pi-list', routerLink: ['logs'] },
{ label: 'System', icon: 'pi pi-fw pi-wave-pulse', routerLink: ['system'] },
Expand Down

This file was deleted.

8 changes: 8 additions & 0 deletions main/http_server/axe-os/src/app/pipes/suffix.pipe.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { SuffixPipe } from './suffix.pipe';

describe('SuffixPipe', () => {
it('create an instance', () => {
const pipe = new SuffixPipe();
expect(pipe).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'hashSuffix'
name: 'suffix'
})
export class HashSuffixPipe implements PipeTransform {
export class SuffixPipe implements PipeTransform {

private static _this = new HashSuffixPipe();
private static _this = new SuffixPipe();

public static transform(value: number): string {
return this._this.transform(value);
Expand All @@ -17,7 +17,7 @@ export class HashSuffixPipe implements PipeTransform {
return '0';
}

const suffixes = [' H/s', ' Kh/s', ' Mh/s', ' Gh/s', ' Th/s', ' Ph/s', ' Eh/s'];
const suffixes = [' ', ' k', ' M', ' G', ' T', ' P', ' E', ' Z', ' Y'];

let power = Math.floor(Math.log10(value) / 3);
if (power < 0) {
Expand All @@ -34,6 +34,4 @@ export class HashSuffixPipe implements PipeTransform {

return scaledValue.toFixed(0) + suffix;
}


}
Loading
Loading