Skip to content

Commit

Permalink
ADD: Fetching Validators for DVT Solutions
Browse files Browse the repository at this point in the history
  • Loading branch information
NeoPlays committed Oct 25, 2024
1 parent e0f9044 commit 3c9f074
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 19 deletions.
84 changes: 70 additions & 14 deletions launcher/src/backend/ValidatorAccountManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,23 +221,38 @@ export class ValidatorAccountManager {
this.nodeConnection.taskManager.otherTasksHandler(ref, `Listing Keys`);
try {
let client = await this.nodeConnection.readServiceConfiguration(serviceID);
const result = await this.keymanagerAPI(client, "GET", "/eth/v1/keystores");
let data = {};
if (client.service === "CharonService" || client.service === "SSVNetworkService") {
const keys = await this.getDVTKeys(serviceID);
data.data = keys.map((dv) => {
return {
validating_pubkey: client.service === "CharonService" ? dv.distributed_public_key : "0x" + dv.public_key,
derivation_path: "",
readonly: false,
dvt: true,
};
});
//Push successful task
this.nodeConnection.taskManager.otherTasksHandler(ref, `Get Keys`, true, data.data);
} else {
const result = await this.keymanagerAPI(client, "GET", "/eth/v1/keystores");

//Error handling
if (SSHService.checkExecError(result) && result.stderr) throw SSHService.extractExecError(result);
if (!result.stdout)
throw `ReturnCode: ${result.rc}\nStderr: ${result.stderr}\nStdout: ${result.stdout}\nIs Your Consensus Client Running?`;
//Error handling
if (SSHService.checkExecError(result) && result.stderr) throw SSHService.extractExecError(result);
if (!result.stdout)
throw `ReturnCode: ${result.rc}\nStderr: ${result.stderr}\nStdout: ${result.stdout}\nIs Your Consensus Client Running?`;

const data = JSON.parse(result.stdout);
if (data.data === undefined) {
if (data.code === undefined || data.message === undefined) {
throw "Undexpected Error: " + result;
data = JSON.parse(result.stdout);
if (data.data === undefined) {
if (data.code === undefined || data.message === undefined) {
throw "Undexpected Error: " + result;
}
throw data.code + " " + data.message;
}
throw data.code + " " + data.message;
}

//Push successful task
this.nodeConnection.taskManager.otherTasksHandler(ref, `Get Keys`, true, result.stdout);
//Push successful task
this.nodeConnection.taskManager.otherTasksHandler(ref, `Get Keys`, true, result.stdout);
}

if (!data.data) data.data = [];
this.writeKeys(data.data.map((key) => key.validating_pubkey));
Expand Down Expand Up @@ -1068,7 +1083,7 @@ export class ValidatorAccountManager {
let charonClient = services.find((service) => service.service === "CharonService");
if (!charonClient) throw "Couldn't find CharonService";
const dataDir = path.posix.join(charonClient.getDataDir(), ".charon");
this.nodeConnection.sshService.exec(`rm -rf ${dataDir}`);
await this.nodeConnection.sshService.exec(`rm -rf ${dataDir}`);
const result = await this.nodeConnection.sshService.uploadDirectorySSH(path.normalize(localPath), dataDir);
if (result) {
log.info("Obol Backup uploaded from: ", localPath);
Expand All @@ -1077,4 +1092,45 @@ export class ValidatorAccountManager {
log.error("Error uploading Obol Backup: ", err);
}
}

async getDVTKeys(serviceID) {
const service = (await this.serviceManager.readServiceConfigurations()).find((s) => s.id === serviceID);
if (!service) throw new Error(`Service with id ${serviceID} not found`);
switch (service.service) {
case "CharonService": {
const result = await this.nodeConnection.sshService.exec(service.getReadClusterLockCommand());
const clusterLock = JSON.parse(result.stdout);
return clusterLock.distributed_validators;
}
case "SSVNetworkService": {
const ssvConfig = await this.nodeConnection.getSSVTotalConfig(serviceID);
//Get Operator ID
const response = await axios.get(
`https://api.ssv.network/api/v4/${service.network}/operators/public_key/` + ssvConfig.privateKeyFileData.publicKey
);
if (response.status !== 200 && !response?.data?.data?.id)
throw new Error(`Couldn't get Operator ID from SSV Network ${response.status} ${response.statusText}`);
const operatorID = response.data.data.id;

//get pagination info
let result = await axios.get(
`https://api.ssv.network/api/v4/${service.network}/validators/in_operator/${operatorID}?page=${1}&perPage=100`
);
if (result.status !== 200) throw new Error(`Couldn't get Validator Keys from SSV Network ${result.status} ${result.statusText}`);

//get all pages and concat them
for (let i = 1; i <= result.data.pagination.pages; i++) {
const page = await axios.get(
`https://api.ssv.network/api/v4/${service.network}/validators/in_operator/${operatorID}?page=${i}&perPage=100`
);
if (page.status !== 200) throw new Error(`Couldn't get Validator Keys from SSV Network ${page.status} ${page.statusText}`);
result.data.validators = result.data.validators.concat(page.data.validators);
}

return result.data.validators;
}
default:
throw new Error(`Service ${service.service} not supported`);
}
}
}
4 changes: 4 additions & 0 deletions launcher/src/backend/ethereum-services/CharonService.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ export class CharonService extends NodeService {
return `ls -1 -a ${this.getDataDir()}/.charon`;
}

getReadClusterLockCommand() {
return `cat ${this.getDataDir()}/.charon/cluster-lock.json`;
}

//definitionFile as URL or Path to file (default ".charon/cluster-definition.json" by dkg command)
getDKGCommand(definitionFile) {
return `docker run -u 0 --name "dkg-container" -d -v "${this.getDataDir()}:/opt/charon" ${this.image + ":" + this.imageVersion} dkg ${
Expand Down
7 changes: 2 additions & 5 deletions launcher/src/composables/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@ export async function useListKeys(forceRefresh) {
const stakingStore = useStakingStore();

let keyStats = [];
let clients = serviceStore.installedServices.filter(
(s) => s.category == "validator" && s.service != "CharonService" && s.service != "SSVNetworkService"
);
let clients = serviceStore.installedServices.filter((s) => s.category == "validator");
if ((clients && clients.length > 0 && nodeManageStore.currentNetwork?.network != "") || forceRefresh) {
for (let client of clients) {
//if there is already a list of keys ()
if ((client.config.keys === undefined || client.config.keys.length === 0 || forceRefresh) && client.state === "running") {
//refresh validaotr list
let result = await ControlService.listValidators(client.config.serviceID);

if (!client.service.includes("Web3Signer")) {
if (!/Web3Signer|CharonService|SSVNetwork/.test(client.service)) {
let resultRemote = await ControlService.listRemoteKeys(client.config.serviceID);
let remoteKeys = resultRemote.data
? resultRemote.data.map((e) => {
Expand Down

0 comments on commit 3c9f074

Please sign in to comment.