Skip to content

Commit

Permalink
indexer-common: Validate cost models in setCostModel
Browse files Browse the repository at this point in the history
I tried baking this right into the sequelize model so that we
could be certain a model is valid before it hits the db, but
I always got errors that `CostModel` was not set on `undefined`,
so something with the `addon` inside the cost model library wasn't
right. Either way, this does what we want it to do.
  • Loading branch information
Jannis committed Jan 15, 2021
1 parent 4dcb26e commit a289e45
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
IndexerManagementFeatures,
} from '../client'
import { defineIndexerManagementModels, IndexerManagementModels } from '../models'
import { CombinedError } from '@urql/core'
import { GraphQLError } from 'graphql'

// Make global Jest variable available
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -580,3 +582,69 @@ describe('Feature: Inject $DAI variable', () => {
).resolves.toHaveProperty('data.costModels', [update])
})
})

describe('Cost model validation', () => {
test('Invalid cost models are rejected', async () => {
const client = await createIndexerManagementClient({
models,
address,
contracts,
logger,
defaults,
features: {
injectDai: false,
},
})

const costModel = {
deployment: '0x0000000000000000000000000000000000000000000000000000000000000000',
model: 'default => 1.0', // semicolon missing
variables: '{}',
}

await expect(
client.mutation(SET_COST_MODEL_MUTATION, { costModel }).toPromise(),
).resolves.toHaveProperty(
'error',
new CombinedError({
graphQLErrors: [
new GraphQLError(
'Invalid cost model or variables: Failed to compile cost model',
),
],
}),
)
})

test('Invalid cost model variables are rejected', async () => {
const client = await createIndexerManagementClient({
models,
address,
contracts,
logger,
defaults,
features: {
injectDai: false,
},
})

const costModel = {
deployment: '0x0000000000000000000000000000000000000000000000000000000000000000',
model: 'default => 1.0;',
variables: '"foo"',
}

await expect(
client.mutation(SET_COST_MODEL_MUTATION, { costModel }).toPromise(),
).resolves.toHaveProperty(
'error',
new CombinedError({
graphQLErrors: [
new GraphQLError(
'Invalid cost model or variables: Failed to compile cost model',
),
],
}),
)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { CostModelVariables, GraphQLCostModel, parseGraphQLCostModel } from '../models'
import { IndexerManagementResolverContext } from '../client'
import { compileAsync } from '@graphprotocol/cost-model'

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getVariable = (vars: CostModelVariables | null, name: string): any | undefined => {
Expand Down Expand Up @@ -68,6 +69,15 @@ export default {
): Promise<object> => {
const update = parseGraphQLCostModel(costModel)

// Validate cost model
try {
const modelForValidation = update.model || 'default => 1;'
const variablesForValidation = JSON.stringify(update.variables || {})
await compileAsync(modelForValidation, variablesForValidation)
} catch (err) {
throw new Error(`Invalid cost model or variables: ${err.message}`)
}

const [model] = await models.CostModel.findOrBuild({
where: { deployment: update.deployment },
})
Expand Down

0 comments on commit a289e45

Please sign in to comment.