Skip to content

Commit 0e6c962

Browse files
tmigoneMaikol
andauthored
Horizon: allocation management (#1123)
Co-authored-by: Maikol <[email protected]>
1 parent da8f53d commit 0e6c962

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3564
-1722
lines changed

packages/indexer-agent/src/agent.ts

Lines changed: 59 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
DeploymentManagementMode,
3939
SubgraphStatus,
4040
sequentialTimerMap,
41+
HorizonTransitionValue,
4142
} from '@graphprotocol/indexer-common'
4243

4344
import PQueue from 'p-queue'
@@ -47,7 +48,11 @@ import mapValues from 'lodash.mapvalues'
4748
import zip from 'lodash.zip'
4849
import { AgentConfigs, NetworkAndOperator } from './types'
4950

50-
type ActionReconciliationContext = [AllocationDecision[], number, bigint]
51+
type ActionReconciliationContext = [
52+
AllocationDecision[],
53+
number,
54+
HorizonTransitionValue,
55+
]
5156

5257
const deploymentInList = (
5358
list: SubgraphDeploymentID[],
@@ -271,21 +276,22 @@ export class Agent {
271276
},
272277
)
273278

274-
const maxAllocationEpochs: Eventual<NetworkMapped<bigint>> =
275-
sequentialTimerMap(
276-
{ logger, milliseconds: requestIntervalLarge },
277-
() =>
278-
this.multiNetworks.map(({ network }) => {
279-
logger.trace('Fetching max allocation epochs', {
280-
protocolNetwork: network.specification.networkIdentifier,
281-
})
282-
return network.contracts.LegacyStaking.maxAllocationEpochs()
283-
}),
284-
{
285-
onError: error =>
286-
logger.warn(`Failed to fetch max allocation epochs`, { error }),
287-
},
288-
)
279+
const maxAllocationDuration: Eventual<
280+
NetworkMapped<HorizonTransitionValue>
281+
> = sequentialTimerMap(
282+
{ logger, milliseconds: requestIntervalLarge },
283+
() =>
284+
this.multiNetworks.map(({ network }) => {
285+
logger.trace('Fetching max allocation duration', {
286+
protocolNetwork: network.specification.networkIdentifier,
287+
})
288+
return network.networkMonitor.maxAllocationDuration()
289+
}),
290+
{
291+
onError: error =>
292+
logger.warn(`Failed to fetch max allocation duration`, { error }),
293+
},
294+
)
289295

290296
const indexingRules: Eventual<NetworkMapped<IndexingRuleAttributes[]>> =
291297
sequentialTimerMap(
@@ -653,7 +659,7 @@ export class Agent {
653659
join({
654660
ticker: timer(requestIntervalLarge),
655661
currentEpochNumber,
656-
maxAllocationEpochs,
662+
maxAllocationDuration,
657663
activeDeployments,
658664
targetDeployments,
659665
activeAllocations,
@@ -663,7 +669,7 @@ export class Agent {
663669
}).pipe(
664670
async ({
665671
currentEpochNumber,
666-
maxAllocationEpochs,
672+
maxAllocationDuration,
667673
activeDeployments,
668674
targetDeployments,
669675
activeAllocations,
@@ -746,7 +752,7 @@ export class Agent {
746752
await this.reconcileActions(
747753
networkDeploymentAllocationDecisions,
748754
currentEpochNumber,
749-
maxAllocationEpochs,
755+
maxAllocationDuration,
750756
)
751757
} catch (err) {
752758
logger.warn(`Exited early while reconciling actions`, {
@@ -1008,18 +1014,25 @@ export class Agent {
10081014
activeAllocations: Allocation[],
10091015
deploymentAllocationDecision: AllocationDecision,
10101016
epoch: number,
1011-
maxAllocationEpochs: bigint,
1017+
maxAllocationDuration: HorizonTransitionValue,
10121018
network: Network,
10131019
): Promise<Allocation[]> {
1014-
const desiredAllocationLifetime = deploymentAllocationDecision.ruleMatch
1015-
.rule?.allocationLifetime
1016-
? deploymentAllocationDecision.ruleMatch.rule.allocationLifetime
1017-
: Math.max(1, Number(maxAllocationEpochs) - 1)
1018-
1019-
// Identify expiring allocations
10201020
let expiredAllocations = activeAllocations.filter(
1021-
allocation =>
1022-
epoch >= allocation.createdAtEpoch + desiredAllocationLifetime,
1021+
async (allocation: Allocation) => {
1022+
let desiredAllocationLifetime: number = 0
1023+
if (allocation.isLegacy) {
1024+
desiredAllocationLifetime = deploymentAllocationDecision.ruleMatch
1025+
.rule?.allocationLifetime
1026+
? deploymentAllocationDecision.ruleMatch.rule.allocationLifetime
1027+
: Math.max(1, maxAllocationDuration.legacy - 1)
1028+
} else {
1029+
desiredAllocationLifetime = deploymentAllocationDecision.ruleMatch
1030+
.rule?.allocationLifetime
1031+
? deploymentAllocationDecision.ruleMatch.rule.allocationLifetime
1032+
: maxAllocationDuration.horizon
1033+
}
1034+
return epoch >= allocation.createdAtEpoch + desiredAllocationLifetime
1035+
},
10231036
)
10241037
// The allocations come from the network subgraph; due to short indexing
10251038
// latencies, this data may be slightly outdated. Cross-check with the
@@ -1029,9 +1042,17 @@ export class Agent {
10291042
expiredAllocations,
10301043
async (allocation: Allocation) => {
10311044
try {
1032-
const onChainAllocation =
1033-
await network.contracts.LegacyStaking.getAllocation(allocation.id)
1034-
return onChainAllocation.closedAtEpoch == 0n
1045+
if (allocation.isLegacy) {
1046+
const onChainAllocation =
1047+
await network.contracts.LegacyStaking.getAllocation(allocation.id)
1048+
return onChainAllocation.closedAtEpoch == 0n
1049+
} else {
1050+
const onChainAllocation =
1051+
await network.contracts.SubgraphService.getAllocation(
1052+
allocation.id,
1053+
)
1054+
return onChainAllocation.closedAt == 0n
1055+
}
10351056
} catch (err) {
10361057
this.logger.warn(
10371058
`Failed to cross-check allocation state with contracts; assuming it needs to be closed`,
@@ -1052,7 +1073,7 @@ export class Agent {
10521073
deploymentAllocationDecision: AllocationDecision,
10531074
activeAllocations: Allocation[],
10541075
epoch: number,
1055-
maxAllocationEpochs: bigint,
1076+
maxAllocationDuration: HorizonTransitionValue,
10561077
network: Network,
10571078
operator: Operator,
10581079
): Promise<void> {
@@ -1128,7 +1149,7 @@ export class Agent {
11281149
activeDeploymentAllocations,
11291150
deploymentAllocationDecision,
11301151
epoch,
1131-
maxAllocationEpochs,
1152+
maxAllocationDuration,
11321153
network,
11331154
)
11341155
if (expiringAllocations.length > 0) {
@@ -1147,7 +1168,7 @@ export class Agent {
11471168
async reconcileActions(
11481169
networkDeploymentAllocationDecisions: NetworkMapped<AllocationDecision[]>,
11491170
epoch: NetworkMapped<number>,
1150-
maxAllocationEpochs: NetworkMapped<bigint>,
1171+
maxAllocationDuration: NetworkMapped<HorizonTransitionValue>,
11511172
): Promise<void> {
11521173
// --------------------------------------------------------------------------------
11531174
// Filter out networks set to `manual` allocation management mode, and ensure the
@@ -1200,14 +1221,14 @@ export class Agent {
12001221
this.multiNetworks.zip3(
12011222
validatedAllocationDecisions,
12021223
epoch,
1203-
maxAllocationEpochs,
1224+
maxAllocationDuration,
12041225
),
12051226
async (
12061227
{ network, operator }: NetworkAndOperator,
12071228
[
12081229
allocationDecisions,
12091230
epoch,
1210-
maxAllocationEpochs,
1231+
maxAllocationDuration,
12111232
]: ActionReconciliationContext,
12121233
) => {
12131234
// Do nothing if there are already approved actions in the queue awaiting execution
@@ -1232,7 +1253,7 @@ export class Agent {
12321253
this.logger.trace(`Reconcile allocation actions`, {
12331254
protocolNetwork: network.specification.networkIdentifier,
12341255
epoch,
1235-
maxAllocationEpochs,
1256+
maxAllocationDuration,
12361257
targetDeployments: allocationDecisions
12371258
.filter(decision => decision.toAllocate)
12381259
.map(decision => decision.deployment.ipfsHash),
@@ -1248,7 +1269,7 @@ export class Agent {
12481269
decision,
12491270
activeAllocations,
12501271
epoch,
1251-
maxAllocationEpochs,
1272+
maxAllocationDuration,
12521273
network,
12531274
operator,
12541275
),

packages/indexer-agent/src/commands/start.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ export const start = {
100100
group: 'Ethereum',
101101
})
102102
.option('confirmation-blocks', {
103-
description: 'The number of blocks to wait for a transaction to be confirmed',
103+
description:
104+
'The number of blocks to wait for a transaction to be confirmed',
104105
type: 'number',
105106
default: 3,
106107
group: 'Ethereum',

packages/indexer-cli/src/__tests__/references/indexer-help.stdout

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ Manage indexer configuration
1010
indexer rules delete Remove one or many indexing rules
1111
indexer rules clear (reset) Clear one or more indexing rules
1212
indexer rules Configure indexing rules
13+
indexer provision thaw Thaw stake from the indexer's provision
14+
indexer provision remove Remove thawed stake from the indexer's provision
15+
indexer provision list-thaw List thaw requests for the indexer's provision
16+
indexer provision get List indexer provision details
17+
indexer provision add Add stake to the indexer's provision
18+
indexer provision Manage indexer's provision
1319
indexer disputes get Cross-check POIs submitted in the network
1420
indexer disputes Configure allocation POI monitoring
1521
indexer cost set model Update a cost model

packages/indexer-cli/src/__tests__/references/indexer.stdout

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ Manage indexer configuration
1010
indexer rules delete Remove one or many indexing rules
1111
indexer rules clear (reset) Clear one or more indexing rules
1212
indexer rules Configure indexing rules
13+
indexer provision thaw Thaw stake from the indexer's provision
14+
indexer provision remove Remove thawed stake from the indexer's provision
15+
indexer provision list-thaw List thaw requests for the indexer's provision
16+
indexer provision get List indexer provision details
17+
indexer provision add Add stake to the indexer's provision
18+
indexer provision Manage indexer's provision
1319
indexer disputes get Cross-check POIs submitted in the network
1420
indexer disputes Configure allocation POI monitoring
1521
indexer cost set model Update a cost model

packages/indexer-cli/src/allocations.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface IndexerAllocation {
2929
queryFeesCollected: bigint
3030
status: string
3131
protocolNetwork: string
32+
isLegacy: boolean
3233
}
3334

3435
const ALLOCATION_CONVERTERS_FROM_GRAPHQL: Record<
@@ -53,6 +54,7 @@ const ALLOCATION_CONVERTERS_FROM_GRAPHQL: Record<
5354
queryFeesCollected: nullPassThrough((x: string) => BigInt(x)),
5455
status: x => x,
5556
protocolNetwork: x => x,
57+
isLegacy: x => x,
5658
}
5759

5860
const ALLOCATION_FORMATTERS: Record<
@@ -76,6 +78,7 @@ const ALLOCATION_FORMATTERS: Record<
7678
queryFeesCollected: x => commify(formatGRT(x)),
7779
status: x => x,
7880
protocolNetwork: resolveChainAlias,
81+
isLegacy: x => (x ? 'Yes' : 'No'),
7982
}
8083

8184
/**
@@ -218,6 +221,8 @@ export const closeAllocation = async (
218221
client: IndexerManagementClient,
219222
allocationID: string,
220223
poi: string | undefined,
224+
blockNumber: number | undefined,
225+
publicPOI: string | undefined,
221226
force: boolean,
222227
protocolNetwork: string,
223228
): Promise<CloseAllocationResult> => {
@@ -227,26 +232,31 @@ export const closeAllocation = async (
227232
mutation closeAllocation(
228233
$allocation: String!
229234
$poi: String
235+
$blockNumber: Int
236+
$publicPOI: String
230237
$force: Boolean
231238
$protocolNetwork: String!
232239
) {
233240
closeAllocation(
234241
allocation: $allocation
235242
poi: $poi
243+
blockNumber: $blockNumber
244+
publicPOI: $publicPOI
236245
force: $force
237246
protocolNetwork: $protocolNetwork
238247
) {
239248
allocation
240249
allocatedTokens
241250
indexingRewards
242-
receiptsWorthCollecting
243251
protocolNetwork
244252
}
245253
}
246254
`,
247255
{
248256
allocation: allocationID,
249257
poi,
258+
blockNumber,
259+
publicPOI,
250260
force,
251261
protocolNetwork,
252262
},
@@ -264,6 +274,8 @@ export const reallocateAllocation = async (
264274
client: IndexerManagementClient,
265275
allocationID: string,
266276
poi: string | undefined,
277+
blockNumber: number | undefined,
278+
publicPOI: string | undefined,
267279
amount: bigint,
268280
force: boolean,
269281
protocolNetwork: string,
@@ -274,20 +286,23 @@ export const reallocateAllocation = async (
274286
mutation reallocateAllocation(
275287
$allocation: String!
276288
$poi: String
289+
$blockNumber: Int
290+
$publicPOI: String
277291
$amount: String!
278292
$force: Boolean
279293
$protocolNetwork: String!
280294
) {
281295
reallocateAllocation(
282296
allocation: $allocation
283297
poi: $poi
298+
blockNumber: $blockNumber
299+
publicPOI: $publicPOI
284300
amount: $amount
285301
force: $force
286302
protocolNetwork: $protocolNetwork
287303
) {
288304
closedAllocation
289305
indexingRewardsCollected
290-
receiptsWorthCollecting
291306
createdAllocation
292307
createdAllocationStake
293308
protocolNetwork
@@ -297,6 +312,8 @@ export const reallocateAllocation = async (
297312
{
298313
allocation: allocationID,
299314
poi,
315+
blockNumber,
316+
publicPOI,
300317
amount: amount.toString(),
301318
force,
302319
protocolNetwork,

0 commit comments

Comments
 (0)