Skip to content

Commit f7ca271

Browse files
authored
Merge branch 'main' into feature/before_merge_testnet
2 parents 080ebd4 + b2b67b4 commit f7ca271

File tree

21 files changed

+447
-34
lines changed

21 files changed

+447
-34
lines changed

build/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ COPY user-settings_template.yml /app/rocketpool/user-settings_template.yml
3535
COPY rocketpool-start.sh /usr/local/bin/rocketpool-start.sh
3636
COPY restart-vc.sh /usr/local/bin/restart-vc.sh
3737
COPY stop-validator.sh /usr/local/bin/stop-validator.sh
38+
COPY stop-supervisor.sh /usr/local/bin/stop-supervisor.sh
3839
RUN chmod +x /usr/local/bin/rocketpool-start.sh
3940
RUN chmod +x /usr/local/bin/restart-vc.sh
4041
RUN chmod +x /usr/local/bin/stop-validator.sh
42+
RUN chmod +x /usr/local/bin/stop-supervisor.sh
4143

4244
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

build/api/src/index.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ app.get("/api/v1/version", (req: Request, res: Response) => {
5151
res.send(version);
5252
});
5353

54+
// POST /api/v1/rocketpool-command-custom
55+
app.post("/api/v1/rocketpool-command-custom", (req: Request, res: Response) => {
56+
console.log(req.body.cmd);
57+
var result = shelljs.exec(
58+
`/usr/local/bin/rocketpoold --settings /app/rocketpool/user-settings.yml api ${req.body.cmd}`
59+
).stdout;
60+
res.send(result);
61+
});
62+
5463
// POST /api/v1/rocketpool-command
5564
app.post("/api/v1/rocketpool-command", (req: Request, res: Response) => {
5665
console.log(req.body.cmd);
@@ -74,16 +83,22 @@ function executeCommand(cmd: string) {
7483
return result;
7584
}
7685

86+
// POST /api/v1/minipool/import
87+
app.post("/api/v1/minipool/import", async (req: Request, res: Response) => {
88+
console.log("Try to import key to the brain");
89+
res.send(await importKey(req.body.pubkey));
90+
});
91+
7792
// function that imports the keys from teku to a given url
78-
function importKey(validatorPubkey: string) {
93+
async function importKey(validatorPubkey: string): Promise<ImportKeyResponseData> {
7994
console.log("Import key to the brain");
8095
var keystoreJson = shelljs.exec(
8196
`cat /rocketpool/data/validators/teku/keys/${validatorPubkey}.json`
8297
).stdout;
8398
var password = shelljs.exec(
8499
`cat /rocketpool/data/validators/teku/passwords/${validatorPubkey}.txt`
85100
).stdout;
86-
postValidatorData({
101+
return await postValidatorData({
87102
keystores: [keystoreJson],
88103
passwords: [password],
89104
tags: ["rocketpool"],
@@ -92,7 +107,7 @@ function importKey(validatorPubkey: string) {
92107
}
93108

94109
// async function to POST fetch
95-
async function postValidatorData(data = {}) {
110+
async function postValidatorData(data = {}): Promise<ImportKeyResponseData> {
96111
const response = await fetch(
97112
`${appConfig.getConfig().brainAPIUrl}/eth/v1/keystores`,
98113
{
@@ -103,9 +118,16 @@ async function postValidatorData(data = {}) {
103118
);
104119
console.log(response.ok);
105120
if (response.ok) {
106-
const { data }: { data: IImportKeyResponseData } = await response.json();
121+
const { data }: { data: ImportKeyResponseData } = await response.json();
107122
console.log(data);
123+
return data;
108124
}
125+
return {
126+
data: [{
127+
status: "error",
128+
message: "Keystore cannot be imported",
129+
}]
130+
};
109131
}
110132

111133
app.listen(API_PORT, () => {
@@ -116,10 +138,10 @@ String.prototype.startsWith = function (str) {
116138
return this.indexOf(str) === 0;
117139
};
118140

119-
interface IImportKeyResponseData {
120-
data: IImportKeyResponse[];
141+
interface ImportKeyResponseData {
142+
data: ImportKeyResponse[];
121143
}
122-
interface IImportKeyResponse {
144+
interface ImportKeyResponse {
123145
status: string;
124146
message?: string;
125147
}

build/stop-supervisor.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/bash
2+
3+
printf "INIT stop-supervisor.sh\n";
4+
5+
while read line; do
6+
echo "Processing Event: $line" >&2;
7+
kill -3 $(cat "/var/run/supervisord.pid")
8+
done < /dev/stdin

build/supervisord.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
[supervisord]
22
nodaemon=true
3+
loglevel=info
4+
logfile=/var/log/supervisor/supervisord.log
5+
pidfile=/var/run/supervisord.pid
6+
childlogdir=/var/log/supervisor
37

48
[program:rocketpool]
59
command=/bin/sh -c "/usr/local/bin/rocketpool-start.sh"
@@ -31,3 +35,7 @@ stdout_logfile=/dev/stdout
3135
stdout_logfile_maxbytes=0
3236
stderr_logfile=/dev/stderr
3337
stderr_logfile_maxbytes=0
38+
39+
[eventlistener:processes]
40+
command=/usr/local/bin/stop-supervisor.sh
41+
events=PROCESS_STATE_STOPPED, PROCESS_STATE_FATAL

build/ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@types/react": "^18.0.28",
1818
"@types/react-dom": "^18.0.11",
1919
"axios": "^1.3.4",
20+
"bignumber.js": "^9.1.1",
2021
"react": "^18.2.0",
2122
"react-dom": "^18.2.0",
2223
"react-scripts": "5.0.1",

build/ui/src/App.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@ import "./App.css";
33
import TopBar from "./components/TopBar/TopBar";
44
import Dashboard from "./Dashboard";
55
import { RocketpoolProvider } from "./components/Providers/Context";
6+
import { Tab } from "./types/Tabs";
67

78
function App() {
8-
const [activeTab, setActiveTab] = useState<string>("Setup");
9+
const [activeTab, setActiveTab] = useState<Tab>("Setup");
910

10-
const handleTabClick = (tab: string) => {
11+
const handleTabClick = (tab: Tab) => {
1112
setActiveTab(tab);
1213
};
1314
return (
1415
<RocketpoolProvider>
1516
<div className="App">
1617
<header className="App-header">
17-
<TopBar onTabClick={(tab: string) => handleTabClick(tab)} />
18+
<TopBar onTabClick={(tab: Tab) => handleTabClick(tab)} />
1819
<Dashboard activeTab={activeTab} />
1920
</header>
2021
</div>

build/ui/src/Dashboard.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { RocketpoolContext } from "./components/Providers/Context";
1111
import RewardsTab from "./components/Rewards/RewardsTab";
1212
import BalanceBox from "./components/BalanceBox/BalanceBox";
1313
import BalanceButton from "./components/Buttons/BalanceButton";
14+
import AdvancedTab from "./components/Advanced/AdvancedTab";
1415

1516
function Dashboard({ activeTab }: { activeTab: string }): JSX.Element {
1617
const { rocketpoolValue, updateRocketpoolValue } =
@@ -42,7 +43,7 @@ function Dashboard({ activeTab }: { activeTab: string }): JSX.Element {
4243
values[2],
4344
values[3],
4445
values[4],
45-
values[5],
46+
values[5]
4647
)
4748
);
4849
setIsLoading(false);
@@ -137,8 +138,11 @@ function Dashboard({ activeTab }: { activeTab: string }): JSX.Element {
137138
{activeTab === "Setup" && (
138139
<SetupTab onRefreshRockpoolData={refreshRocketpoolData} />
139140
)}
140-
{activeTab === "Rewards" && <RewardsTab config={rocketpoolValue.config} />}
141+
{activeTab === "Rewards" && (
142+
<RewardsTab config={rocketpoolValue.config} />
143+
)}
141144
{activeTab === "Info" && <InfoTab />}
145+
{activeTab === "Advanced" && <AdvancedTab />}
142146
</div>
143147
</Card>
144148
)}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import React, { useEffect, useRef, useState } from "react";
2+
import {
3+
Alert,
4+
AlertTitle,
5+
Box,
6+
TextField,
7+
Button,
8+
CircularProgress,
9+
} from "@mui/material";
10+
import { AppService } from "../../services/AppService";
11+
12+
interface AdvancedTabProps {}
13+
14+
const AdvancedTab: React.FC<AdvancedTabProps> = (): JSX.Element => {
15+
const [command, setCommand] = useState<string>("");
16+
const [output, setOutput] = useState<string>("");
17+
const [loadingCommand, setLoadingCommand] = useState<boolean>(false);
18+
const appService = new AppService();
19+
20+
const outputRef = useRef<HTMLDivElement | null>(null);
21+
22+
useEffect(() => {
23+
// Scroll to the bottom of the TextField whenever the output is updated
24+
if (outputRef.current) {
25+
outputRef.current.scrollTop = outputRef.current.scrollHeight;
26+
}
27+
}, [output]);
28+
29+
const handleCommandChange = (event: React.ChangeEvent<HTMLInputElement>) => {
30+
setCommand(event.target.value);
31+
};
32+
33+
const handleSubmit = async (event: React.FormEvent) => {
34+
setLoadingCommand(true);
35+
event.preventDefault();
36+
37+
const output = await appService.runCustomCommand(command);
38+
39+
// Append the command and output to the output box
40+
setOutput((prevOutput) => prevOutput + `>> ${command}\n${output}\n\n`);
41+
42+
// Clear the input field
43+
setCommand("");
44+
setLoadingCommand(false);
45+
};
46+
47+
return (
48+
<div>
49+
<div style={{ display: "flex", justifyContent: "center" }}>
50+
<Box width={"40rem"} p={2}>
51+
<Alert severity="warning" variant="filled">
52+
<AlertTitle>Advanced Users Only</AlertTitle>
53+
This tab is designed for advanced users. It allows sending commands
54+
to the rocketpool binary and displays the output obtained.
55+
</Alert>
56+
</Box>
57+
</div>
58+
59+
<Box
60+
sx={{
61+
px: 4,
62+
}}
63+
>
64+
<Box
65+
mt={2}
66+
p={1}
67+
height={300}
68+
overflow="auto"
69+
borderRadius={1}
70+
sx={{ backgroundColor: "grey.200" }}
71+
ref={outputRef}
72+
>
73+
<pre
74+
style={{
75+
whiteSpace: "pre-wrap",
76+
margin: 0,
77+
fontFamily: "Ubuntu Mono, monospace",
78+
fontSize: "14px",
79+
lineHeight: "1.4",
80+
color: "#555555",
81+
textAlign: "left",
82+
overflowWrap: "break-word",
83+
wordBreak: "break-all",
84+
}}
85+
>
86+
{output}
87+
</pre>
88+
</Box>
89+
<form
90+
onSubmit={handleSubmit}
91+
style={{ display: "flex", marginTop: "16px" }}
92+
>
93+
<TextField
94+
label="Enter Command (Example: node status)"
95+
value={command}
96+
onChange={handleCommandChange}
97+
fullWidth
98+
InputProps={{
99+
disableUnderline: true,
100+
style: {
101+
fontFamily: "Ubuntu Mono, monospace",
102+
fontSize: "14px",
103+
lineHeight: "1.4",
104+
color: "#555555",
105+
},
106+
}}
107+
InputLabelProps={{
108+
style: {
109+
fontFamily: "Ubuntu Mono, monospace",
110+
fontSize: "14px",
111+
lineHeight: "1.4",
112+
color: "#555555",
113+
},
114+
}}
115+
sx={{ backgroundColor: "grey.200" }}
116+
/>
117+
{!loadingCommand ? (
118+
<Button
119+
type="submit"
120+
variant="contained"
121+
color="primary"
122+
style={{ marginLeft: "1rem" }}
123+
disabled={command === ""}
124+
>
125+
Submit
126+
</Button>
127+
) : (
128+
<CircularProgress style={{ marginLeft: "1rem" }} />
129+
)}
130+
</form>
131+
</Box>
132+
</div>
133+
);
134+
};
135+
136+
export default AdvancedTab;

build/ui/src/components/Rewards/RewardsTab.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Config } from "../../types/AppConfig";
1515
import TxsLinksBox from "../Setup/TxsLinksBox";
1616
import { CanClaimRewards } from "../../types/CanClaimRewards";
1717
import { TxResponse } from "../../types/TxResponse";
18+
import BigNumber from "bignumber.js";
1819

1920
interface RewardsTabProps {
2021
config?: Config;
@@ -56,13 +57,13 @@ const RewardsTab: React.FC<RewardsTabProps> = ({
5657
.map((reward) => reward.index)
5758
.join(",");
5859
const sumCollateralRplAmount = rewardsInfo.unclaimedIntervals.reduce(
59-
(accumulator, currentValue) => accumulator + Number(currentValue.collateralRplAmount),
60-
0
60+
(accumulator, currentValue) => accumulator.plus(new BigNumber(currentValue.collateralRplAmount)),
61+
new BigNumber(0),
6162
);
6263
var canClainRewards = restake
6364
? await appService.getNodeCanClaimAndRestakeRewards(
6465
indexes,
65-
sumCollateralRplAmount,
66+
sumCollateralRplAmount.toString(),
6667
)
6768
: await appService.getNodeCanClaimRewards(indexes);
6869
setNodeCanClaimRewards(canClainRewards);
@@ -72,7 +73,7 @@ const RewardsTab: React.FC<RewardsTabProps> = ({
7273
var tx = restake
7374
? await appService.nodeClaimAndRestakeRewards(
7475
indexes,
75-
sumCollateralRplAmount,
76+
sumCollateralRplAmount.toString(),
7677
)
7778
: await appService.nodeClaimRewards(indexes);
7879
setTxResponse(tx);

0 commit comments

Comments
 (0)