Skip to content

Commit 8d954eb

Browse files
committed
feat: renaming gupaxx to gupax
updated the README to not focus on XvB anymore but presenting Gupax globally in a simple way. Some portion of the original README of gupax will be moved to documentation. Gupax v2 will check if gupaxx was used more recently than gupax and will apply the settings from it if gupax last use wasn't v2. fix
1 parent a3cf5af commit 8d954eb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+965
-910
lines changed

ADMIN.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
## Why does Gupax need to be Admin? (on Windows)
2+
**TL;DR:** Because Windows.
3+
4+
**Slightly more detailed TL;DR:** Rust does not have mature Win32 API wrapper libraries. Although Microsoft has an official ["Rust" library](https://github.com/microsoft/windows-rs), it is quite low-level and using it within Gupax would mean re-implementing a lot of Rust's STDLIB process module code.
5+
6+
If you are confused because you use Gupax on macOS/Linux, this is a Windows-only issue.
7+
8+
The following sections will go more into the technical issues I've encountered in trying to implement something that sounds pretty trivial: Starting a child process with elevated privilege, and getting a handle to it and its output. (it's a rant about windows).
9+
10+
---
11+
12+
### The issue
13+
`XMRig` needs to be run with administrative privileges to enable MSR mods and hugepages. There are other ways of achieving this through pretty manual and technical efforts (which also gets more complicated due to OS differences) but in the best interest of Gupax's users, I always want to implement things so that it's **easy for the user.**
14+
15+
Users should not need to be familiar with MSRs to get max hashrate, this is something the program (me, Gupax!) should do for them.
16+
17+
---
18+
19+
### The requirements
20+
Process's in Gupax need the following criteria met:
21+
- I (as the parent process, Gupax) *must* have a direct handle to the process so that I can send SIGNALs
22+
- I *must* have a handle to the process's STDOUT+STDERR so that I can actually relay output to the user
23+
- I *really should* but don't absolutely need a handle to STDIN so that I can send input from the user
24+
25+
In the case of XMRig, **I absolutely must enable MSR's automatically for the user**, that's the whole point of XMRig, that's the point of an easy-to-use GUI.
26+
Although I want XMRig with elevated rights, I don't want these side-effects:
27+
- All of Gupax running as Admin
28+
- P2Pool running as Admin
29+
30+
Here are the "solutions" I've attempted:
31+
32+
---
33+
34+
### CMD's RunAs
35+
Window has a `runas` command, which allows for privilege escalation. Perfect! Spawn a shell and it's easy as running this:
36+
```
37+
runas /user:Administrator xmrig.exe [...]
38+
```
39+
...right?
40+
41+
The `Administrator` in this context is a legacy account, not meant to be touched, not really the `Admin` we are looking for, but more importantly: the password is not set, and the entire account is disabled by default. This means you cannot actually `runas` as *that* `Administrator`. Technically, all it would take is for the user to enabled the account and set a password. But that is already asking for too much, remember: that's my job, to make this **easy and automatic**. So this is a no-go, next.
42+
43+
---
44+
45+
### PowerShell's Start-Process
46+
Window's `PowerShell` has a nice built-in called [`Start-Process`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-7.3). This allows PowerShell to start... processes. In particular, I was intrigued by the all-in-one flag: `-Verb RunAs`, which runs the provided process with elevated permissions after a **UAC prompt.** That sounds perfect... except if you click that link you'll see 2 sets of syntax. IF you are escalating privilege, Microsoft puts a lot more retrictions on what you can do with this built-in, in particular:
47+
- You CANNOT redirect STDOUT/STDERR/STDIN
48+
- You CANNOT run the process in the current shell (a new PowerShell window will always open!)
49+
50+
I attempted some hacks like chaining non-admin PowerShell + admin PowerShell together, which made things overly complicated and meant I would be handling logic within these child PowerShell's which would be controlled via STDIN from Gupax code... Not very robust. I also tried just starting an admin PowerShell directly from Gupax, but that meant the user, upon clicking `[Start]` for XMRig, would see a UAC prompt to open PowerShell, which wasn't a good look. Eventually I gave up on PowerShell, next.
51+
52+
---
53+
54+
### Win32's ShellExecuteW
55+
This was the first option I came across, but I intentionally ignored it due to many reasons. Microsoft has official Windows API bindings in [Rust](https://github.com/microsoft/windows-rs). That library has a couple problems:
56+
1. All (the entire library) code requires `unsafe`
57+
2. It's extremely low-level
58+
59+
The first one isn't actually as bad as it seems, this is Win32 so it's battle-tested. It's also extern C, so it makes sense it has to wrapped in `unsafe`.
60+
61+
The second one is the real issue. [ShellExecuteW](https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew) is a Win32 function that allows exactly what I need, starting a process with elevated privilege with the `runas` flag. It even shows the UAC to the user. But... that's it! No other functionality. The highly abstracted `Command` type in Rust's STDLIB actually uses [`CreateProcessW`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw), and due to type imcompatabilities, using `ShellExecuteW` on my own would mean re-implementing ALL the functionality Rust STDLIB gives, aka: handling STDOUT, STDERR, STDIN, sending SIGNALS, waiting on process, etc etc. I would be programming for "Windows", not "Rust". Okay... next.
62+
63+
---
64+
65+
### Registry Edit
66+
To start a process in Windows with elevated escalation you can right-click -> `Run as Administrator`, but you can also set a permanent flag deeper in the file's options. In reality this sets a Registry Key with the absolute path to that executable and a `RUNASADMIN` flag. This allows Windows to know which programs to run as an admin. There is a Rust library called [`WinReg`](https://github.com/gentoo90/winreg-rs) that provides functionality to read/write to the Registry. Editing the Registry is akin to editing someone's `.bashrc`, it's a sin! But... if it means **automatically applying the MSR mod** and **better UX**, then yes I will. The flow would have been:
67+
- User starts XMRig
68+
- Gupax notices XMRig is not admin
69+
- Gupax tells user
70+
- Gupax gives option to AUTOMATICALLY edit registry
71+
- Gupax also gives the option to show how to do it manually
72+
73+
This was the solution I would have gone with, but alas, the abstracted `Command` types I am using to start processes completely ignore this metadata. When Gupax starts XMRig, that `Run as Administrator` flag is completely ignored. Grrr... what options are left?
74+
75+
---
76+
77+
### Windows vs Unix
78+
Unix (macOS/Linux) has a super nice, easy, friendly, not-completely-garbage userland program called: `sudo`. It is so extremely simple to use `sudo` as a sort of wrapper around XMRig since `sudo` isn't completely backwards and actually has valuable flags! No legacy `Administrator`, no UAC prompt, no shells within shells, no low-level system APIs, no messing with the user Registry.
79+
80+
You get the user's password, you input it to `sudo` with `--stdin` and you execute XMRig with it. Simple, easy, nice. (Don't forget to zero the password memory, though).
81+
82+
With no other option left on Windows, I unfortunately have to fallback to the worst solution: shipping Gupax's binary to have `Administrator` metadata, so that it will automatically prompt users for UAC. This means all child process spawned by Gupax will ALSO have admin rights. Windows having one of the most complicated spaghetti privilege systems is ironically what led me to use the most unsecure option.
83+
84+
Depending on the privilege used, Gupax will error/panic:
85+
- Windows: If not admin, warn the user about potential lower XMRig hashrate
86+
- Unix: IF admin, panic! Don't allow anything. As it should be.
87+
88+
If you're reading this and have a solution (that isn't using Win32), please... please teach me.

ARCHITECTURE.md

Lines changed: 133 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Gupaxx ARCHITECTURE
1+
# Gupax ARCHITECTURE
22

3-
This document explains how the source code is organized. Everything differing from [Gupax](https://github.com/hinto-janai/gupax) is described here. Things that are not changed will not be present.
3+
** This file needs updating**
44

55
## Structure
66
| File/Folder | Purpose |
@@ -26,23 +26,145 @@ This document explains how the source code is organized. Everything differing fr
2626
|helper/xvb/nodes.rs| Manage connection of XvB nodes.
2727
|helper/xvb/rounds.rs| Struct for Rounds with printing and detecting of current round.
2828
|helper/xvb/public\|private_stats| Struct to retrieve public and private stats with request.
29-
|component| Gupaxx related features, like updates and nodes.
29+
|component| Gupax related features, like updates and nodes.
3030

3131

32-
## Technical differences of column XMRig in Status Tab process sub-menu with upstream Gupax
32+
33+
## Thread Model
34+
![thread_model.png](./assets/images/thread_model.png)
35+
36+
Process's (both Simple/Advanced) have:
37+
- 1 OS thread for the watchdog (API fetching, watching signals, etc)
38+
- 1 OS thread for a PTY-Child combo (combines STDOUT/STDERR for me, nice!)
39+
- A PTY (pseudo terminal) whose underlying type is abstracted with the [`portable_pty`](https://docs.rs/portable-pty/) library
40+
41+
The reason why STDOUT/STDERR is non-async is because P2Pool requires a `TTY` to take STDIN. The PTY library used, [`portable_pty`](https://docs.rs/portable-pty/), doesn't implement async traits. There seem to be tokio PTY libraries, but they are Unix-specific. Having separate PTY code for Windows/Unix is also a big pain. Since the threads will be sleeping most of the time (the pipes are lazily read and buffered), it's fine. Ideally, any I/O should be a tokio task, though.
42+
43+
## Bootstrap
44+
This is how Gupax works internally when starting up:
45+
46+
1. **INIT**
47+
- Initialize custom console logging with `log`, `env_logger`
48+
- Initialize misc data (structs, text styles, thread count, images, etc)
49+
- Start initializing main `App` struct
50+
- Parse command arguments
51+
- Attempt to read disk files
52+
- If errors were found, set the `panic` error screen
53+
54+
2. **AUTO**
55+
- If `auto_update` == `true`, spawn auto-updating thread
56+
- If `auto_ping` == `true`, spawn remote node ping thread
57+
- If `auto_p2pool` == `true`, spawn P2Pool
58+
- If `auto_xmrig` == `true`, spawn XMRig
59+
60+
3. **MAIN**
61+
- All data should be initialized at this point, either via `state.toml` or default options
62+
- Start `App` frame
63+
- Do `App` stuff
64+
- If `ask_before_quit` == `true`, ask before quitting
65+
- Kill processes, kill connections, exit
66+
67+
## Scale
68+
Every frame, the max available `[width, height]` are calculated, and those are used as a baseline for the Top/Bottom bars, containing the tabs and status bar. After that, all available space is given to the middle ui elements. The scale is calculated every frame so that all elements can scale immediately as the user adjusts it; this doesn't take as much CPU as you might think since frames are only rendered on user interaction. Some elements are subtracted a fixed number because the `ui.separator()`'s add some fixed space which needs to be accounted for.
69+
70+
```
71+
Main [App] outer frame (default: [1280.0, 960.0], 4:3 aspect ratio)
72+
├─ TopPanel = height: 1/15
73+
├─ BottomPanel = height: 1/22
74+
├─ CentralPanel = height: the rest
75+
```
76+
77+
## Naming Scheme
78+
This is the internal naming scheme used by Gupax when updating/creating default folders/etc:
79+
80+
Windows:
81+
```
82+
Gupax\
83+
├─ Gupax.exe
84+
├─ P2Pool\
85+
│ ├─ p2pool.exe
86+
├─ XMRig\
87+
├─ xmrig.exe
88+
```
89+
90+
macOS (Gupax is packaged as an `.app` on macOS):
91+
```
92+
Gupax.app/Contents/MacOS/
93+
├─ gupax
94+
├─ p2pool/
95+
│ ├─ p2pool
96+
├─ xmrig/
97+
├─ xmrig
98+
```
99+
100+
Linux:
101+
```
102+
gupax/
103+
├─ gupax
104+
├─ p2pool/
105+
│ ├─ p2pool
106+
├─ xmrig/
107+
├─ xmrig
108+
```
109+
110+
When Gupax updates, it walks the directories of the extracted `zip/tar` searching for a valid file. These are the valid filenames Gupax will match against and assume is the new binary we're looking for:
111+
- `[GUPAX, Gupax, gupax]`
112+
- `[P2POOL, P2Pool, P2pool, p2pool]`
113+
- `[XMRIG, XMRig, Xmrig, xmrig]`
114+
115+
Windows versions of Gupax also need the file to end with `.exe`.
116+
117+
The actual `zip/tar` matching is static, however. They have to be packaged exactly with the following naming scheme. If an exact match is not found, it will error:
118+
- `gupax-vX.X.X-(windows|macos|linux)-(x64|arm64)-(standalone|bundle).(zip|tar.gz)`
119+
- `p2pool-vX.X.X-(windows|macos|linux)-(x64|aarch64).(zip|tar.gz)`
120+
- `xmrig-X.X.X-(msvc-win64|macos-x64|macos-arm64|linux-static-x64).(zip|tar.gz)`
121+
122+
Exceptions (there are always exceptions...):
123+
- XMRig doesn't have a [v], so it is [xmrig-6.18.0-...]
124+
- XMRig separates the hash and signature
125+
- P2Pool hashes are in UPPERCASE
126+
127+
## Mining Stat Reference
128+
Some pseudo JSON for constants/equations needed for generating mining stats. They're here for easy reference, I was never good at math :)
129+
```
130+
block_time_in_seconds: {
131+
P2POOL_BLOCK_TIME: 10,
132+
MONERO_BLOCK_TIME: 120,
133+
}
134+
135+
difficulty: {
136+
P2POOL_DIFFICULTY: (current_p2pool_hashrate * P2POOL_BLOCK_TIME),
137+
MONERO_DIFFICULTY: (current_monero_hashrate * MONERO_BLOCK_TIME),
138+
}
139+
140+
hashrate_per_second: {
141+
P2POOL_HASHRATE: (P2POOL_DIFFICULTY / P2POOL_BLOCK_TIME),
142+
MONERO_HASHRATE: (MONERO_DIFFICULTY / MONERO_BLOCK_TIME),
143+
}
144+
145+
mean_in_seconds: {
146+
P2POOL_BLOCK_MEAN: (MONERO_DIFF / P2POOL_HASHRATE),
147+
MY_SOLO_BLOCK_MEAN: (MONERO_DIFF / my_hashrate),
148+
MY_P2POOL_SHARE_MEAN: (P2POOL_DIFF / my_hashrate),
149+
}
150+
```
151+
152+
153+
154+
## Technical differences of column XMRig in Status Tab process sub-menu with old Gupax
33155

34156
Status of process for XMRig use for some information an image of data when the process started.
35-
The node of xmrig in upstream can not change without a restart of the process. In this fork, the node used by XMRig needs to be updated without restart (using the config HTTP API of XMRig).
36-
So Gupaxx needs to refresh the value of status tab submenu process for XMRig where before the values could not change without a restart of the process.
157+
The node of xmrig in could not change without a restart of the process. In this fork, the node used by XMRig needs to be updated without restart (using the config HTTP API of XMRig).
158+
So Gupax needs to refresh the value of status tab submenu process for XMRig where before the values could not change without a restart of the process.
37159
The field node from ImgXmrig needs to be moved to PubXvbApi. This value must be updated by XMRig at start and by XvB process at runtime.
38160

39161
## Updates
40162

41-
A new option in Gupaxx tab advanced will enable bundled updates.
42-
The binary included of Gupaxx will have default value for bundled updates depending if it is coming from the standalone or the bundled release.
163+
A new option in Gupax tab advanced will enable bundled updates.
164+
The binary included of Gupax will have default value for bundled updates depending if it is coming from the standalone or the bundled release.
43165

44-
Updates from Gupaxx will do the following differently from upstream:
45-
- Check if using bundled or standalone with state. Update only Gupaxx binary if the latter or xmrig and p2pool from bundle version if the former.
166+
Updates from Gupax will do the following differently from before v2:
167+
- Check if using bundled or standalone with state. Update only Gupax binary if the latter or xmrig and p2pool from bundle version if the former.
46168
- Prevent user to run updates twice without restart.
47-
- Ask the user to restart Gupaxx.
169+
- Ask the user to restart Gupax.
48170
- Do not verify if file P2Pool or XMRig exist. (so that the update can create them).

0 commit comments

Comments
 (0)