From 09c79f09e904426f03c8fb932edf6d5407d9f8be Mon Sep 17 00:00:00 2001 From: POPPIN-FUMI Date: Fri, 28 Jun 2024 09:37:32 +0200 Subject: [PATCH 1/4] update - solv setup --- packages/solv/src/cli/setup/index.ts | 1 - packages/solv/src/cli/setup/setup.ts | 81 ++++----------------- packages/solv/src/cli/setup/setupMount.ts | 69 ++++++++++++++++++ packages/solv/src/cli/setup/testnetSetup.ts | 81 --------------------- 4 files changed, 83 insertions(+), 149 deletions(-) create mode 100644 packages/solv/src/cli/setup/setupMount.ts delete mode 100644 packages/solv/src/cli/setup/testnetSetup.ts diff --git a/packages/solv/src/cli/setup/index.ts b/packages/solv/src/cli/setup/index.ts index d5b04af..83068c5 100644 --- a/packages/solv/src/cli/setup/index.ts +++ b/packages/solv/src/cli/setup/index.ts @@ -7,7 +7,6 @@ import { readOrCreateDefaultConfig, } from '@/lib/readOrCreateDefaultConfig' import { createSolvKeyPairs } from '@/lib/createSolvKeys' -import { testnetSetup } from './testnetSetup' import { setupSwap } from './setupSwap' type SetupOptions = { diff --git a/packages/solv/src/cli/setup/setup.ts b/packages/solv/src/cli/setup/setup.ts index 8de6fa0..3e12f86 100644 --- a/packages/solv/src/cli/setup/setup.ts +++ b/packages/solv/src/cli/setup/setup.ts @@ -1,26 +1,15 @@ -import { execSync, spawnSync } from 'child_process' -import { setupDirs } from '@/cli/setup/mkdirs' +import { execSync } from 'child_process' import { setupKeys } from '@/cli/setup/setupKeys' import { genStartupValidatorScript } from '@/cli/setup/genStartupValidatorScript' import { Logger } from '@/lib/logger' import chalk from 'chalk' import { makeServices } from '@/cli/setup/makeServices' import { setupPermissions } from '@/cli/setup/userPermissions' -import { umount } from '@/cli/check/mt/umount' import getPreferredDisk, { GetPreferredDisksResult, } from '../check/mt/getLargestDisk' import { startSolana } from '@/cli/start/startSolana' -import { - CONFIG, - DISK_TYPES, - MAINNET_TYPES, - NETWORK_TYPES, - RPC_MODE, - SOLV_TYPES, -} from '@/config/config' -import { ensureFstabEntries } from '@/cli/check/ensureMountAndFiles' -import { formatDisk } from '@/cli/setup/formatDisk' +import { CONFIG, MAINNET_TYPES, RPC_MODE, SOLV_TYPES } from '@/config/config' import { updateSolvConfig } from '@/lib/updateSolvConfig' import inquirer from 'inquirer' import { @@ -37,10 +26,11 @@ import { askJitoSetting } from './askJitoSetting' import { readOrCreateJitoConfig } from '@/lib/readOrCreateJitoConfig' import { updateFirewall } from './updateFirewall' import { updateJitoSolvConfig } from '@/lib/updateJitoSolvConfig' -import { getRootFreeSpaceGB, setupSwap } from './setupSwap' +import { getRootFreeSpaceGB } from './setupSwap' import { jitoRelayerSetup } from './jitoRelayerSetup' import { createSymLink } from './createSymLink' import { getSnapshot } from '../get/snapshot' +import setupMount from './setupMount' export const setup = async (solvConfig: ConfigParams) => { try { @@ -94,7 +84,7 @@ export const setup = async (solvConfig: ConfigParams) => { type: 'confirm', message: 'Do you want to setup as a dummy(Inactive) node?(※For Migration)', - default: false, + default: true, }, ]) // Check if the root volume is larger than 256GB @@ -175,68 +165,25 @@ export const setup = async (solvConfig: ConfigParams) => { } console.log(`Setting up ${solvType}...`) + // Check if there is enough disk space const disks: GetPreferredDisksResult = getPreferredDisk() + + // Skip mounting disk if there is not enough disk space if (!disks.has400GB && !disks.has850GB && !disks.hasUsed1250GB) { console.log( chalk.yellow( - `⚠️ Not enough disk space to setup Solana Validator\nYou need at least 1TB disk space\nPlease add more disk space and try again!`, + `⚠️ Not enough disk space to setup Solana Validator\nYou need at least 1TB disk space\nSkip mounting disk...`, ), ) - return - } - - const mountPoint = disks.disks[0].mountpoint - setupDirs() - // Detect if DISK_TYPE is DOUBLE or SINGLE - if (disks.has850GB && disks.has400GB) { - // DOUBLE - console.log('Setting up DOUBLE DISK...') - - updateSolvConfig({ - DISK_TYPES: DISK_TYPES.DOUBLE, - SOLV_TYPE: sType, - COMMISSION: commission, - SOLANA_NETWORK: isTest ? NETWORK_TYPES.TESTNET : NETWORK_TYPES.MAINNET, - }) - - const fileSystemName1 = '/dev/' + disks.disks[0].name - const fileSystemName2 = '/dev/' + disks.disks[1].name - const isDisk1Formatted = formatDisk(fileSystemName1) - const isDisk2Formatted = formatDisk(fileSystemName2) - - // Swap setup - await setupSwap(askSwapsize.swapsize) - - let fileSystem1 = isDisk1Formatted ? fileSystemName1 : '' - let fileSystem2 = isDisk2Formatted ? fileSystemName2 : '' - let isLatitude = false - if (fileSystem1 === '' && fileSystem2) { - fileSystem1 = fileSystem2 - fileSystem2 = '' - isLatitude = true - } - ensureFstabEntries(fileSystem1, fileSystem2, isLatitude) } else { - // SINGLE - console.log('Setting up SINGLE DISK...') - updateSolvConfig({ - DISK_TYPES: DISK_TYPES.SINGLE, - SOLV_TYPE: sType, - COMMISSION: commission, - }) - if (!mountPoint.includes('/mnt')) { - const fileSystem = '/dev/' + disks.disks[0].name - formatDisk(fileSystem) - ensureFstabEntries(fileSystem) - } else { - umount(mountPoint) - const fileSystem = '/dev/' + disks.disks[0].name - formatDisk(fileSystem) - ensureFstabEntries(fileSystem) - } + // Mount the disk + await setupMount(askSwapsize.swapsize, disks, sType, commission, isTest) } + const newSolvConfig = readOrCreateDefaultConfig() setupPermissions() + + // Generate startup script await genStartupValidatorScript( true, sType, diff --git a/packages/solv/src/cli/setup/setupMount.ts b/packages/solv/src/cli/setup/setupMount.ts new file mode 100644 index 0000000..597afcb --- /dev/null +++ b/packages/solv/src/cli/setup/setupMount.ts @@ -0,0 +1,69 @@ +import { updateSolvConfig } from '@/lib/updateSolvConfig' +import { ensureFstabEntries } from '../check/ensureMountAndFiles' +import { DISK_TYPES, NETWORK_TYPES, SOLV_TYPES } from '@/config/config' +import { formatDisk } from './formatDisk' +import { umount } from '../check/mt/umount' +import { setupSwap } from './setupSwap' +import { GetPreferredDisksResult } from '../check/mt/getLargestDisk' +import { setupDirs } from './mkdirs' + +const setupMount = async ( + swapsize: number, + disks: GetPreferredDisksResult, + solvType: SOLV_TYPES, + commission: number, + isTest: boolean, +) => { + const mountPoint = disks.disks[0].mountpoint + setupDirs() + // Detect if DISK_TYPE is DOUBLE or SINGLE + if (disks.has850GB && disks.has400GB) { + // DOUBLE + console.log('Setting up DOUBLE DISK...') + + updateSolvConfig({ + DISK_TYPES: DISK_TYPES.DOUBLE, + SOLV_TYPE: solvType, + COMMISSION: commission, + SOLANA_NETWORK: isTest ? NETWORK_TYPES.TESTNET : NETWORK_TYPES.MAINNET, + }) + + const fileSystemName1 = '/dev/' + disks.disks[0].name + const fileSystemName2 = '/dev/' + disks.disks[1].name + const isDisk1Formatted = formatDisk(fileSystemName1) + const isDisk2Formatted = formatDisk(fileSystemName2) + + // Swap setup + await setupSwap(swapsize) + + let fileSystem1 = isDisk1Formatted ? fileSystemName1 : '' + let fileSystem2 = isDisk2Formatted ? fileSystemName2 : '' + let isLatitude = false + if (fileSystem1 === '' && fileSystem2) { + fileSystem1 = fileSystem2 + fileSystem2 = '' + isLatitude = true + } + ensureFstabEntries(fileSystem1, fileSystem2, isLatitude) + } else { + // SINGLE + console.log('Setting up SINGLE DISK...') + updateSolvConfig({ + DISK_TYPES: DISK_TYPES.SINGLE, + SOLV_TYPE: solvType, + COMMISSION: commission, + }) + if (!mountPoint.includes('/mnt')) { + const fileSystem = '/dev/' + disks.disks[0].name + formatDisk(fileSystem) + ensureFstabEntries(fileSystem) + } else { + umount(mountPoint) + const fileSystem = '/dev/' + disks.disks[0].name + formatDisk(fileSystem) + ensureFstabEntries(fileSystem) + } + } +} + +export default setupMount diff --git a/packages/solv/src/cli/setup/testnetSetup.ts b/packages/solv/src/cli/setup/testnetSetup.ts deleted file mode 100644 index c3f8ded..0000000 --- a/packages/solv/src/cli/setup/testnetSetup.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { spawnSync } from 'child_process' -import { setupDirs } from '@/cli/setup/mkdirs' -import { setupKeys } from '@/cli/setup/setupKeys' -import { genStartupValidatorScript } from '@/cli/setup/genStartupValidatorScript' -import chalk from 'chalk' -import { makeServices } from '@/cli/setup/makeServices' -import { setupPermissions } from '@/cli/setup/userPermissions' -import { umount } from '@/cli/check/mt/umount' -import getPreferredDisk, { - GetPreferredDisksResult, -} from '@/cli/check/mt/getLargestDisk' -import { startSolana } from '@/cli/start/startSolana' -import { CONFIG, DISK_TYPES, SOLV_TYPES } from '@/config/config' -import { ensureFstabEntries } from '@/cli/check/ensureMountAndFiles' -import { formatDisk } from '@/cli/setup/formatDisk' -import { updateSolvConfig } from '@/lib/updateSolvConfig' -import { ConfigParams } from '@/lib/readOrCreateDefaultConfig' -import { langSet } from '@/lib/langSet' - -export const testnetSetup = async (solvConfig: ConfigParams) => { - try { - const isTest = true - const commission = CONFIG.COMMISSION - const sType = SOLV_TYPES.TESTNET_VALIDATOR - - const disks: GetPreferredDisksResult = getPreferredDisk() - const mountPoint = disks.disks[0].mountpoint - setupDirs() - // Detect if DISK_TYPE is DOUBLE or SINGLE - if (disks.has850GB && disks.has400GB) { - // DOUBLE - console.log('Setting up DOUBLE DISK...') - - updateSolvConfig({ - DISK_TYPES: DISK_TYPES.DOUBLE, - SOLV_TYPE: sType, - COMMISSION: commission, - }) - const fileSystem = '/dev/' + disks.disks[0].name - formatDisk(fileSystem) - const fileSystem2 = '/dev/' + disks.disks[1].name - formatDisk(fileSystem2) - ensureFstabEntries(fileSystem, fileSystem2) - } else { - // SINGLE - console.log('Setting up SINGLE DISK...') - updateSolvConfig({ - DISK_TYPES: DISK_TYPES.SINGLE, - SOLV_TYPE: sType, - COMMISSION: commission, - }) - if (!mountPoint.includes('/mnt')) { - const fileSystem = '/dev/' + disks.disks[0].name - formatDisk(fileSystem) - ensureFstabEntries(fileSystem) - } else { - umount(mountPoint) - const fileSystem = '/dev/' + disks.disks[0].name - formatDisk(fileSystem) - ensureFstabEntries(fileSystem) - } - } - setupPermissions() - await genStartupValidatorScript(true, sType) - makeServices(isTest) - setupKeys(solvConfig) - const cmds = [ - 'sudo systemctl daemon-reload', - 'sudo systemctl enable solv', - 'sudo systemctl restart logrotate', - ] - for (const line of cmds) { - spawnSync(line, { shell: true, stdio: 'inherit' }) - } - startSolana() - updateSolvConfig({ IS_SETUP: true }) - return true - } catch (error) { - throw new Error(`setup Error: ${error}`) - } -} From aaae07a5628c31077539a7f9cc3b26357c80a200 Mon Sep 17 00:00:00 2001 From: POPPIN-FUMI Date: Fri, 28 Jun 2024 09:38:47 +0200 Subject: [PATCH 2/4] update - solv log --- packages/solv/src/cli/log/tail.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/solv/src/cli/log/tail.ts b/packages/solv/src/cli/log/tail.ts index 70d2892..257d909 100644 --- a/packages/solv/src/cli/log/tail.ts +++ b/packages/solv/src/cli/log/tail.ts @@ -11,7 +11,7 @@ export type TailOptions = { export const tail = (options: TailOptions) => { try { const { log } = startupScriptPaths() - let cmd = `tail -f ${log}*` + let cmd = `tail -f ${log}` if (options.error) { cmd += ` | grep '\\(WARN\\|ERR\\)'` } else if (options.info) { From c283cf298b55cbcde2e3c6b30ffd1e7a9b2eb1d6 Mon Sep 17 00:00:00 2001 From: POPPIN-FUMI Date: Fri, 28 Jun 2024 09:43:37 +0200 Subject: [PATCH 3/4] add - solv df/du --- packages/solv/src/cli/check/df/index.ts | 11 +++++++++-- packages/solv/src/index.ts | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/solv/src/cli/check/df/index.ts b/packages/solv/src/cli/check/df/index.ts index 6c7e94f..d4938c2 100644 --- a/packages/solv/src/cli/check/df/index.ts +++ b/packages/solv/src/cli/check/df/index.ts @@ -1,16 +1,23 @@ import { program } from '@/index' import { df } from './df' import { displayTable } from '@/lib/logger/table' -import { Logger } from '@/lib/logger' +import { logDiskUsage } from './du' export const dfCommands = async () => { program .command('df') .description('Disk Free Command') - .action(async () => { + .action(() => { const dirs = df() displayTable(dirs) }) + + program + .command('du') + .description('Disk Usage Command') + .action(() => { + logDiskUsage() + }) } export const convertToBytes = (size: string): number => { diff --git a/packages/solv/src/index.ts b/packages/solv/src/index.ts index d91ec01..3503876 100644 --- a/packages/solv/src/index.ts +++ b/packages/solv/src/index.ts @@ -19,6 +19,7 @@ import { clientCommands, mountCommands, relayerCommands, + dfCommands, } from '@/cli' import { balanceCommands } from './cli/balance' import { rmLogs } from './cli/setup/rmLogs' @@ -76,6 +77,7 @@ async function main() { transferCommands(solvConfig) withdrawCommands(solvConfig) harvestCommands(solvConfig) + dfCommands() program .command('rm:log') From 5c1451e93695ce7364939967ccd43b2b03388c12 Mon Sep 17 00:00:00 2001 From: POPPIN-FUMI Date: Fri, 28 Jun 2024 10:47:16 +0200 Subject: [PATCH 4/4] Added - solv harvest/transfer/epochTimer --- .changeset/wild-hounds-happen.md | 88 +++++++++++++++++++++ .github/workflows/solv-cli-release.yml | 2 +- packages/solv/README.md | 12 +++ packages/solv/src/cli/check/df/df.ts | 11 ++- packages/solv/src/cli/check/df/index.ts | 8 -- packages/solv/src/cli/server/server.ts | 14 ---- packages/solv/src/cli/server/stake/index.ts | 1 - packages/solv/src/cli/stake/index.ts | 16 +--- 8 files changed, 109 insertions(+), 43 deletions(-) create mode 100644 .changeset/wild-hounds-happen.md diff --git a/.changeset/wild-hounds-happen.md b/.changeset/wild-hounds-happen.md new file mode 100644 index 0000000..e618685 --- /dev/null +++ b/.changeset/wild-hounds-happen.md @@ -0,0 +1,88 @@ +--- +'@epics-dao/solv': patch +--- + +## New Features - v4.2.0~v4.2.1 + +- Added Solana Liquid Staking Command +- Added Solana Transfer Command +- Added Auto Reward Harvest Command +- Added Epoch Timer +- Improved setup command +- Improved log command +- Added solv df command +- Migrated to ESM Module +- Added Turbo Repo + +* You should set the SOLANA_RPC_URL in the .env file to use this feature effectively. + +### Solana Liquid Staking Command + +```bash +$ solv stake --lst +``` + +### Solana Transfer Command + +```bash +$ solv transfer/tr +``` + +### Auto Reward Harvest Command + +This command collects all rewards into the authority account, converts the gathered SOL to elSOL, and then transfers the elSOL to an external harvest account. + +This ensures that, in the event of a node hack, assets are not held within the node. Additionally, it allows immediate staking of rewards, thereby enhancing performance. + +※ To use this command, you must first set the harvest account in the solv.config.json file. During the initial execution, you can input this information interactively. + +Please ensure that this account information is never stored on the validator server. + +```bash +$ solv harvest/hv +``` + +Soon, we will be adding the ability to run the harvest command by the epochTimer. + +### Epoch Timer + +The epochTimer is a feature that allows you to set a specific time to run the some commands. +This feature is especially useful for those who want to stake rewards at before the epoch change. + +- You need to set `DISCORD_WEBHOOK_URL` in the `.env` file to use this feature. + +```bash +$ solv epochTimer +``` + +### Improved setup command + +The setup command has been improved to allow you to set up without mounting the volume. + +```bash +$ solv setup +``` + +### Improved log command + +small bug fixes and improvements + +```bash +$ solv log +``` + +### Added solv df command + +This command shows the disk usage of the validator server. + +```bash +$ solv df +``` + +### Migrated to ESM Module + +solv has been migrated to ESM Module. + +### Added Turbo Repo + +We have added a Turbo Repo to manage the solv package. diff --git a/.github/workflows/solv-cli-release.yml b/.github/workflows/solv-cli-release.yml index cdc96be..1d95eb7 100644 --- a/.github/workflows/solv-cli-release.yml +++ b/.github/workflows/solv-cli-release.yml @@ -30,7 +30,7 @@ jobs: run: pnpm install - name: Build and Add Line - run: npx turbo build -F @epics-dao/solv + run: npx turbo -F @epics-dao/solv build - name: Creating .npmrc run: | diff --git a/packages/solv/README.md b/packages/solv/README.md index e348384..b254a68 100755 --- a/packages/solv/README.md +++ b/packages/solv/README.md @@ -68,6 +68,18 @@ $ solv start This will remove the snapshot and restart the Solana Validator from the new snapshot. +## New Features - v4.2.0~v4.2.1 + +- Added Solana Liquid Staking Command +- Added Solana Transfer Command +- Added Auto Reward Harvest Command +- Added Epoch Timer +- Improved setup command +- Improved log command +- Added solv df command +- Migrated to ESM Module +- Added Turbo Repo + ## New Features - v4.0.0~v4.1.0 - Jito Relayer Setup diff --git a/packages/solv/src/cli/check/df/df.ts b/packages/solv/src/cli/check/df/df.ts index 14fc5a6..c2d0f0c 100644 --- a/packages/solv/src/cli/check/df/df.ts +++ b/packages/solv/src/cli/check/df/df.ts @@ -1,7 +1,6 @@ import { UbuntuDhParams } from '@/types/solvTypes' import { execSync } from 'child_process' import { convertToBytes } from '.' -import { Logger } from '@/lib/logger' export const df = () => { const output = execSync('df -h').toString() @@ -56,11 +55,11 @@ export const df = () => { ) .map((data) => data.Filesystem) if (fsNames.length > 0) { - console.log( - Logger.warningHex( - `\nfileSystem might be one of ${fsNames.join(', ')} ...?`, - ), - ) + // console.log( + // Logger.warningHex( + // `\nfileSystem might be one of ${fsNames.join(', ')} ...?`, + // ), + // ) } } diff --git a/packages/solv/src/cli/check/df/index.ts b/packages/solv/src/cli/check/df/index.ts index d4938c2..efb283e 100644 --- a/packages/solv/src/cli/check/df/index.ts +++ b/packages/solv/src/cli/check/df/index.ts @@ -1,7 +1,6 @@ import { program } from '@/index' import { df } from './df' import { displayTable } from '@/lib/logger/table' -import { logDiskUsage } from './du' export const dfCommands = async () => { program @@ -11,13 +10,6 @@ export const dfCommands = async () => { const dirs = df() displayTable(dirs) }) - - program - .command('du') - .description('Disk Usage Command') - .action(() => { - logDiskUsage() - }) } export const convertToBytes = (size: string): number => { diff --git a/packages/solv/src/cli/server/server.ts b/packages/solv/src/cli/server/server.ts index a7312b7..637e972 100644 --- a/packages/solv/src/cli/server/server.ts +++ b/packages/solv/src/cli/server/server.ts @@ -22,20 +22,6 @@ export enum INSTALLER_CHOICES { } export const server = async (solvConfig: ConfigParams) => { - const homeDir = os.homedir() - if (solvConfig.config.IS_CLIENT) { - console.log( - chalk.yellow( - `⚠️ Please run solv server from the server, not from the your local machine -Or You might need to - -${chalk.white('$ su solv')} - -to login as solv user...?`, - ), - ) - return - } Logger.solvAA() const { logs, installer, cmds } = solvConfig.locale const { config } = solvConfig diff --git a/packages/solv/src/cli/server/stake/index.ts b/packages/solv/src/cli/server/stake/index.ts index ea5c758..b7f5267 100644 --- a/packages/solv/src/cli/server/stake/index.ts +++ b/packages/solv/src/cli/server/stake/index.ts @@ -8,7 +8,6 @@ import { delegateStake } from '@/cli/stake' import { stakeAccountQuestion } from '@/cli/stake/stakeAccountQuestion' import { deactivateStake } from '@/cli/stake/deactivateStake' import { withdrawStake } from '@/cli/stake/withdrawStake' -import { updateSolvConfig } from '@/lib/updateSolvConfig' import { delegateStakeAsk } from './delegateStakeAsk' import { unstakeAsk } from './unstakeAsk' import { deactivateStakeAsk } from './deactivateStakeAsk' diff --git a/packages/solv/src/cli/stake/index.ts b/packages/solv/src/cli/stake/index.ts index cd794cb..b157ced 100644 --- a/packages/solv/src/cli/stake/index.ts +++ b/packages/solv/src/cli/stake/index.ts @@ -1,4 +1,4 @@ -import { SOLANA_RPC_URL, program } from '@/index' +import { program } from '@/index' import { delegateStake } from './delegateStake' export * from './delegateStake' import { @@ -13,22 +13,12 @@ import { deactivateStakeAsk } from '../server/stake/deactivateStakeAsk' import { unstakeAsk } from '../server/stake/unstakeAsk' import { withdrawStakeAsk } from '../server/stake/withdrawStakeAsk' import chalk from 'chalk' -import { - ELSOL_MINT_ADDRESS, - NETWORK_TYPES, - SOLV_ELSOL_ACCOUNT_ADDRESS, - SOLV_STAKE_POOL_ADDRESS, -} from '@/config/config' +import { NETWORK_TYPES, SOLV_STAKE_POOL_ADDRESS } from '@/config/config' import { selectLST } from './selectLST' -import { Connection, Keypair, PublicKey } from '@solana/web3.js' import { readFile } from 'fs/promises' -import { depositSol } from '@/lib/solana/depositSOL' import inquirer from 'inquirer' import { homedir } from 'os' -import { PriorityLevel } from '@/lib/solana/priorityFee' -import { getOrCreateDestinationAddress } from '@/lib/solana/getOrCreateDestinationAddress' -import { existsAsync, sleep } from '@skeet-framework/utils' -import { Spinner } from 'cli-spinner' +import { existsAsync } from '@skeet-framework/utils' import { elSOLdeposit } from './elSOLdeposit' import { depositeLST } from './depositLST' import { execSync } from 'child_process'