Skip to content

Commit

Permalink
Stakingv4 preparations (#1255)
Browse files Browse the repository at this point in the history
* add queue size in stake endpoint

* implemented better heuristic

* stake invalidation

* invalidate stake every 30 seconds

* exclude leaving validators in shard info

* add stakingV4 devnet/mainnet configs

* update stake.spec.ts

* secondary sorting criteria

* reverse sorting

* cached nodes auctions, invalidated if staking v4 enabled

* update activationEpoch

---------

Co-authored-by: cfaur <[email protected]>
  • Loading branch information
tanghel and cfaur09 authored May 21, 2024
1 parent 73303c5 commit d49b7d0
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 8 deletions.
4 changes: 4 additions & 0 deletions config/config.devnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ features:
admins:
- ''
jwtSecret: ''
stakingV4:
enabled: false
cronExpression: '*/5 * * * * *'
activationEpoch: 1043
nodeEpochsLeft:
enabled: false
transactionProcessor:
Expand Down
4 changes: 4 additions & 0 deletions config/config.mainnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ features:
admins:
- ''
jwtSecret: ''
stakingV4:
enabled: false
cronExpression: '*/5 * * * * *'
activationEpoch: 1391
nodeEpochsLeft:
enabled: false
transactionProcessor:
Expand Down
13 changes: 12 additions & 1 deletion src/crons/cache.warmer/cache.warmer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { BlockService } from "src/endpoints/blocks/block.service";
import { PoolService } from "src/endpoints/pool/pool.service";
import * as JsonDiff from "json-diff";
import { QueryPagination } from "src/common/entities/query.pagination";
import { StakeService } from "src/endpoints/stake/stake.service";

@Injectable()
export class CacheWarmerService {
Expand Down Expand Up @@ -64,6 +65,7 @@ export class CacheWarmerService {
private readonly dataApiService: DataApiService,
private readonly blockService: BlockService,
private readonly poolService: PoolService,
private readonly stakeService: StakeService,
) {
this.configCronJob(
'handleTokenAssetsInvalidations',
Expand Down Expand Up @@ -137,8 +139,10 @@ export class CacheWarmerService {
const auctions = await this.gatewayService.getValidatorAuctions();

await this.nodeService.processAuctions(nodes, auctions);

await this.invalidateKey(CacheInfo.Nodes.key, nodes, CacheInfo.Nodes.ttl);

const nodesAuctions = await this.nodeService.getAllNodesAuctionsRaw();
await this.invalidateKey(CacheInfo.NodesAuctions.key, nodesAuctions, CacheInfo.NodesAuctions.ttl);
}

@Lock({ name: 'Transaction pool invalidation', verbose: true })
Expand Down Expand Up @@ -206,6 +210,13 @@ export class CacheWarmerService {
await this.invalidateKey(CacheInfo.Economics.key, economics, CacheInfo.Economics.ttl);
}

@Cron(CronExpression.EVERY_30_SECONDS)
@Lock({ name: 'Stake invalidations', verbose: true })
async handleStakeInvalidations() {
const stake = await this.stakeService.getGlobalStakeRaw();
await this.invalidateKey(CacheInfo.GlobalStake.key, stake, CacheInfo.GlobalStake.ttl);
}

@Cron(CronExpression.EVERY_MINUTE)
@Lock({ name: 'Accounts invalidations', verbose: true })
async handleAccountInvalidations() {
Expand Down
23 changes: 18 additions & 5 deletions src/endpoints/nodes/node.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -721,12 +721,19 @@ export class NodeService {
return nodes;
}

async getNodesAuctions(pagination: QueryPagination, filter: NodeAuctionFilter): Promise<NodeAuction[]> {
async getAllNodesAuctions(): Promise<NodeAuction[]> {
return await this.cacheService.getOrSet(
CacheInfo.NodesAuctions.key,
async () => await this.getAllNodesAuctionsRaw(),
CacheInfo.NodesAuctions.ttl
);
}

async getAllNodesAuctionsRaw(): Promise<NodeAuction[]> {
const allNodes = await this.getNodes(new QueryPagination({ size: 10000 }), new NodeFilter({ status: NodeStatus.auction }));

const auctions = await this.gatewayService.getValidatorAuctions();
const auctionNodesMap = new Map();
const { from, size } = pagination;

for (const auction of auctions) {
if (auction.nodes) {
Expand All @@ -741,7 +748,7 @@ export class NodeService {

const groupedNodes = allNodes.groupBy(node => (node.provider || node.owner) + ':' + (BigInt(node.stake).toString()) + (BigInt(node.topUp).toString()), true);

let nodesWithAuctionData: NodeAuction[] = [];
const nodesWithAuctionData: NodeAuction[] = [];

for (const group of groupedNodes) {
const node: Node = group.values[0];
Expand Down Expand Up @@ -772,15 +779,21 @@ export class NodeService {
nodesWithAuctionData.push(nodeAuction);
}

return nodesWithAuctionData;
}

async getNodesAuctions(pagination: QueryPagination, filter: NodeAuctionFilter): Promise<NodeAuction[]> {
let nodesWithAuctionData = await this.getAllNodesAuctions();

const sort = filter?.sort ?? NodeSortAuction.qualifiedStake;
const order = !filter?.sort && !filter?.order ? SortOrder.desc : filter?.order;
nodesWithAuctionData = nodesWithAuctionData.sorted(node => Number(node[sort]));
nodesWithAuctionData = nodesWithAuctionData.sorted(node => Number(node[sort]), node => node.qualifiedAuctionValidators === 0 ? 0 : 1, node => 0 - node.droppedValidators);

if (order === SortOrder.desc) {
nodesWithAuctionData.reverse();
}

return nodesWithAuctionData.slice(from, size);
return nodesWithAuctionData.slice(pagination.from, pagination.size);
}

async deleteOwnersForAddressInCache(address: string): Promise<string[]> {
Expand Down
2 changes: 1 addition & 1 deletion src/endpoints/shards/shard.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class ShardService {
({ type, shard, status }) =>
type === 'validator' &&
shard !== undefined &&
[NodeStatus.eligible, NodeStatus.waiting, NodeStatus.leaving].includes(status ?? NodeStatus.unknown)
[NodeStatus.eligible, NodeStatus.waiting].includes(status ?? NodeStatus.unknown)
);

const shards = validators.map(({ shard }) => shard).filter(shard => shard !== undefined).map(shard => shard ?? 0).distinct();
Expand Down
4 changes: 3 additions & 1 deletion src/endpoints/stake/stake.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export class StakeService {
const totalStaked = BigInt(BigInt(totalBaseStaked) + BigInt(totalTopUp)).toString();
const totalObservers = await this.nodeService.getNodeCount(new NodeFilter({ type: NodeType.observer }));

if (!this.apiConfigService.isStakingV4Enabled()) {
const currentEpoch = await this.blockService.getCurrentEpoch();

if (!this.apiConfigService.isStakingV4Enabled() || currentEpoch < this.apiConfigService.getStakingV4ActivationEpoch()) {
const queueSize = await this.nodeService.getNodeCount(new NodeFilter({ status: NodeStatus.queued }));
return new GlobalStake({
totalValidators: validators.totalValidators,
Expand Down
2 changes: 2 additions & 0 deletions src/test/unit/services/stake.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe('Stake Service', () => {
getStakingContractAddress: jest.fn(),
getAuctionContractAddress: jest.fn(),
isStakingV4Enabled: jest.fn(),
getStakingV4ActivationEpoch: jest.fn(),
},
},
{
Expand Down Expand Up @@ -168,6 +169,7 @@ describe('Stake Service', () => {
jest.spyOn(stakeService, 'getMinimumAuctionTopUp').mockResolvedValue(expectedMinimumAuctionQualifiedTopUp);
jest.spyOn(stakeService, 'getNakamotoCoefficient').mockResolvedValue(expectedNakamotoCoefficient);
jest.spyOn(apiConfigService, 'isStakingV4Enabled').mockReturnValue(true);
jest.spyOn(apiConfigService, 'getStakingV4ActivationEpoch').mockReturnValue(1395);
jest.spyOn(nodeService, 'getNodeCount').mockResolvedValue(100);

const result = await stakeService.getGlobalStakeRaw();
Expand Down
5 changes: 5 additions & 0 deletions src/utils/cache.info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -640,4 +640,9 @@ export class CacheInfo {
ttl: Constants.oneMinute(),
};
}

static NodesAuctions: CacheInfo = {
key: 'nodesAuctions',
ttl: Constants.oneMinute(),
};
}

0 comments on commit d49b7d0

Please sign in to comment.