Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add various 'at-block' programs and 'chain' programs #5

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions programs/chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { program } from '@command';
import { getLatestBlock } from '@utils';

const accounts = program.command('chain').description('chain utils');

accounts
.command('latest-block')
.description('get latest block')
.action(async () => {
const block = await getLatestBlock();

const formatOptions: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
timeZoneName: 'short',
hour12: false,
};
const intl = new Intl.DateTimeFormat('en-GB', formatOptions);

console.table({
number: block.number,
hash: block.hash,
timestamp: block.timestamp,
datetime: intl.format(block.timestamp * 1000),
});
});
166 changes: 93 additions & 73 deletions programs/common/consensus.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { authorizedCall, getLatestBlock } from '@utils';
import {authorizedCall, getBlock, getLatestBlock, parseBlock } from '@utils';
import { Command } from 'commander';
import { Contract, EventLog, formatEther } from 'ethers';
import { BlockTag, Contract, EventLog, formatEther } from 'ethers';

export const addConsensusCommands = (command: Command, contract: Contract) => {
command
Expand Down Expand Up @@ -133,83 +133,23 @@ export const addConsensusCommands = (command: Command, contract: Contract) => {

command
.command('closest-report')
.description('returns the closest report')
.action(async () => {
const chainConfig = await contract.getChainConfig();
const frameConfig = await contract.getFrameConfig();

const secondsPerSlot = Number(chainConfig.secondsPerSlot);
const genesisTime = Number(chainConfig.genesisTime);
const slotsPerEpoch = Number(chainConfig.slotsPerEpoch);

const initialEpoch = Number(frameConfig.initialEpoch);
const epochsPerFrame = Number(frameConfig.epochsPerFrame);

const computeFrameIndex = (timestamp: number) => {
const epoch = Math.floor((timestamp - genesisTime) / secondsPerSlot / slotsPerEpoch);
return Math.floor((epoch - initialEpoch) / epochsPerFrame);
};

const getFrame = (frameIndex: number) => {
const frameStartEpoch = Math.floor(initialEpoch + frameIndex * epochsPerFrame);
const frameStartSlot = frameStartEpoch * slotsPerEpoch;
const nextFrameStartSlot = frameStartSlot + epochsPerFrame * slotsPerEpoch;

return {
index: frameIndex,
refSlot: frameStartSlot - 1,
reportProcessingDeadlineSlot: nextFrameStartSlot - 1,
};
};

const formatOptions: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
timeZoneName: 'short',
hour12: false,
};
const intl = new Intl.DateTimeFormat('en-GB', formatOptions);

const slotToTime = (slot: number) => {
const time = (genesisTime + slot * secondsPerSlot) * 1000;
return intl.format(time);
};

const nowUnix = Math.floor(Date.now() / 1000);
const currentSlot = Math.floor((nowUnix - genesisTime) / secondsPerSlot);

const currentFrame = getFrame(computeFrameIndex(nowUnix));
const nextFrame = getFrame(currentFrame.index + 1);
.description('returns the closest report for the latest or specific block')
.option('-b, --block <number>', 'block (number or string)', 'latest')
.action(async (options: { block: string }) => {
const blockTag = parseBlock(options.block);
const report = await getClosestReport(contract, blockTag);

const getFrameSlots = (frame: { refSlot: number; reportProcessingDeadlineSlot: number }) => {
const refSlot = frame.refSlot;
const deadlineSlot = frame.reportProcessingDeadlineSlot;

return [
{ value: 'ref slot', slot: refSlot, time: slotToTime(refSlot) },
{ value: 'deadline slot', slot: deadlineSlot, time: slotToTime(deadlineSlot) },
];
};

console.log('current slot');
console.table([
{
value: 'current slot',
slot: currentSlot,
time: slotToTime(currentSlot),
},
]);
console.log(`closest-report for block ${blockTag}`);
console.log('target slot');
console.table(report.targetSlot);

console.log();
console.log('current report frame');
console.table(getFrameSlots(currentFrame));
console.log('target report frame');
console.table(report.targetReportFrame);

console.log();
console.log('next report frame');
console.table(getFrameSlots(nextFrame));
console.table(report.nextReportFrame);
});

command
Expand Down Expand Up @@ -254,3 +194,83 @@ export const addConsensusCommands = (command: Command, contract: Contract) => {
console.table(groupedByRefSlot);
});
};

/**
* Get closest report for specific slot
*/
export const getClosestReport = async (contract: Contract, blockTag: BlockTag) => {
const isNow = blockTag === 'latest';

const latestBlock = await getBlock(blockTag);
const nowUnix = latestBlock.timestamp;
const chainConfig = await contract.getChainConfig({ blockTag });
const frameConfig = await contract.getFrameConfig({ blockTag });

const secondsPerSlot = Number(chainConfig.secondsPerSlot);
const genesisTime = Number(chainConfig.genesisTime);
const slotsPerEpoch = Number(chainConfig.slotsPerEpoch);

const initialEpoch = Number(frameConfig.initialEpoch);
const epochsPerFrame = Number(frameConfig.epochsPerFrame);

const computeFrameIndex = (timestamp: number) => {
const epoch = Math.floor((timestamp - genesisTime) / secondsPerSlot / slotsPerEpoch);
return Math.floor((epoch - initialEpoch) / epochsPerFrame);
};

const getFrame = (frameIndex: number) => {
const frameStartEpoch = Math.floor(initialEpoch + frameIndex * epochsPerFrame);
const frameStartSlot = frameStartEpoch * slotsPerEpoch;
const nextFrameStartSlot = frameStartSlot + epochsPerFrame * slotsPerEpoch;

return {
index: frameIndex,
refSlot: frameStartSlot - 1,
reportProcessingDeadlineSlot: nextFrameStartSlot - 1,
};
};

const formatOptions: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
timeZoneName: 'short',
hour12: false,
};
const intl = new Intl.DateTimeFormat('en-GB', formatOptions);

const slotToTime = (slot: number) => {
const time = (genesisTime + slot * secondsPerSlot) * 1000;
return intl.format(time);
};

const currentSlot = Math.floor((nowUnix - genesisTime) / secondsPerSlot);

const currentFrame = getFrame(computeFrameIndex(nowUnix));
const nextFrame = getFrame(currentFrame.index + 1);

const getFrameSlots = (frame: { refSlot: number; reportProcessingDeadlineSlot: number }) => {
const refSlot = frame.refSlot;
const deadlineSlot = frame.reportProcessingDeadlineSlot;

return [
{ value: 'ref slot', slot: refSlot, time: slotToTime(refSlot) },
{ value: 'deadline slot', slot: deadlineSlot, time: slotToTime(deadlineSlot) },
];
};

const report = {
targetSlot: [{
value: isNow ? 'current slot' : `slot at ${blockTag}`,
slot: currentSlot,
block: latestBlock.number,
time: slotToTime(currentSlot),
}],
targetReportFrame: getFrameSlots(currentFrame),
nextReportFrame: getFrameSlots(nextFrame)
};

return report;
}
24 changes: 22 additions & 2 deletions programs/dsm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { program } from '@command';
import { dsmContract } from '@contracts';
import { authorizedCall } from '@utils';
import { dsmContract, stakingRouterContract } from '@contracts';
import { authorizedCall, getLatestBlock } from '@utils';
import { addLogsCommands, addParsingCommands } from './common';

const dsm = program.command('dsm').description('interact with deposit security module contract');
Expand Down Expand Up @@ -146,3 +146,23 @@ dsm
.action(async (moduleId) => {
await authorizedCall(dsmContract, 'unpauseDeposits', [moduleId]);
});

dsm
.command('can-deposit-block-distance')
.description('check deposits according to block distance condition')
.argument('<moduleId>', 'staking module id')
.action(async (moduleId) => {
const block = await getLatestBlock();
const lastDepositBlock = await stakingRouterContract.getStakingModuleLastDepositBlock(moduleId);
const minDepositBlockDistance = await dsmContract.getMinDepositBlockDistance();

const result = block.number - lastDepositBlock >= minDepositBlockDistance;

console.table({
blockNumber: block.number,
lastDepositBlock: lastDepositBlock,
minDepositBlockDistance: minDepositBlockDistance,
condition: 'blockNumber - lastDepositBlock >= minDepositBlockDistance',
result: result,
});
});
1 change: 1 addition & 0 deletions programs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './accounting-consensus';
export * from './accounting-oracle';
export * from './accounts';
export * from './burner';
export * from './chain';
export * from './deposit-contract';
export * from './dsm';
export * from './exit-bus-consensus';
Expand Down
8 changes: 8 additions & 0 deletions programs/lido.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ lido
console.log('is stopped', isStopped);
});

lido
.command('can-deposit')
.description('returns is protocol can deposit')
.action(async () => {
const canDeposit = await lidoContract.canDeposit();
console.log('can deposit', canDeposit);
});

lido
.command('is-staking-paused')
.description('returns is staking paused')
Expand Down
6 changes: 3 additions & 3 deletions programs/staking-module/modules.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { stakingRouterContract } from '@contracts';
import { Result } from 'ethers';
import { BlockTag, Result } from 'ethers';

export type StakingModule = {
id: number;
Expand All @@ -14,8 +14,8 @@ export type StakingModule = {
exitedValidatorsCount: number;
};

export const getStakingModules = async (): Promise<StakingModule[]> => {
const modules: Result[] = await stakingRouterContract.getStakingModules();
export const getStakingModules = async (blockTag?: BlockTag): Promise<StakingModule[]> => {
const modules: Result[] = await stakingRouterContract.getStakingModules({ blockTag });
return modules.map((module) => {
const {
id,
Expand Down
8 changes: 5 additions & 3 deletions programs/staking-router.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { program } from '@command';
import { stakingRouterContract } from '@contracts';
import { authorizedCall } from '@utils';
import { authorizedCall, parseBlock } from '@utils';
import { Result } from 'ethers';
import { addAccessControlSubCommands, addLogsCommands, addOssifiableProxyCommands, addParsingCommands } from './common';
import { getNodeOperators, getStakingModules } from './staking-module';
Expand All @@ -14,8 +14,10 @@ addLogsCommands(router, stakingRouterContract);
router
.command('modules')
.description('returns staking modules')
.action(async () => {
const modules = await getStakingModules();
.option('-b, --block <number>', 'block (number or string)', 'latest')
.action(async (options: { block: string }) => {
const blockTag = parseBlock(options.block);
const modules = await getStakingModules(blockTag);
console.log('modules', modules);
});

Expand Down
11 changes: 11 additions & 0 deletions programs/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,14 @@ validators
const result = await postToAttestationPool(attesterSlashing);
console.log(result);
});


validators
.command('info')
.description('fetches validator info by pubkey or validator index')
.argument('<indexOrPubkey>', 'validator index of pubkey')
.action(async (indexOrPubkey: string) => {
const validator = await fetchValidator(indexOrPubkey);

console.log('validator', validator);
});
12 changes: 12 additions & 0 deletions utils/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,15 @@ export const getBlock = async (blockTag: BlockTag) => {

return block;
};

export const parseBlock = (block: string) => {
const isNumeric = (value: string) => {
return /^-?\d+$/.test(value);
}

if (isNumeric(block)) {
return parseInt(block, 10);
}

return block;
};