Skip to content

Commit 5eaba3f

Browse files
committed
manifest-schema,src/subgraph: Add data to EthereumBlockhandler, validate
1 parent 4bdaa47 commit 5eaba3f

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

manifest-schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type EthereumContractAbi {
4242

4343
type EthereumBlockHandler {
4444
handler: String!
45+
input: String
4546
filter: EthereumBlockFilter
4647
}
4748

src/subgraph.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ let { strOptions } = require('yaml/types')
66
let graphql = require('graphql/language')
77
let validation = require('./validation')
88
let ABI = require('./abi')
9+
let asc = require('assemblyscript')
910

1011
const throwCombinedError = (filename, errors) => {
1112
throw new Error(
@@ -317,6 +318,76 @@ ${abiFunctions
317318
}, immutable.List())
318319
}
319320

321+
static validateBlockFunctions(manifest, { resolveFile }) {
322+
return manifest
323+
.get('dataSources')
324+
.filter(
325+
dataSource =>
326+
dataSource.get('kind') === 'ethereum/contract' &&
327+
dataSource.getIn(['mapping', 'blockHandlers'], immutable.List()).count() > 0,
328+
)
329+
.reduce((errors, dataSource, dataSourceIndex) => {
330+
let path = ['dataSources', dataSourceIndex, 'blockHandlers']
331+
// Use the Assemblyscript parser to generate an AST from the mapping file
332+
let mappingFile = dataSource.getIn(['mapping', 'file'])
333+
let mappingParser = new asc.Parser()
334+
mappingParser.parseFile(
335+
fs.readFileSync(resolveFile(mappingFile), 'utf-8'),
336+
'',
337+
false,
338+
)
339+
340+
let blockHandlers = dataSource.getIn(
341+
['mapping', 'blockHandlers'],
342+
immutable.List(),
343+
)
344+
345+
// Ensure each blockHandler has a corresponding mapping handler
346+
// with a compatible function signature
347+
return errors.concat(
348+
blockHandlers.reduce(
349+
(errors, handler, index) =>
350+
mappingParser.program.sources
351+
.filter(source => source.kind == asc.SourceKind.DEFAULT)
352+
.some(source =>
353+
source.statements
354+
.filter(
355+
statement => statement.kind === asc.NodeKind.FUNCTIONDECLARATION,
356+
)
357+
.some(
358+
functionDeclaration =>
359+
functionDeclaration.name.text === handler.get('handler') &&
360+
functionDeclaration.signature.parameters.length === 1 &&
361+
functionDeclaration.signature.parameters[0].name.text ==
362+
'block' &&
363+
functionDeclaration.signature.parameters[0].type.name.identifier
364+
.text === 'ethereum' &&
365+
functionDeclaration.signature.parameters[0].type.name.next
366+
.identifier.text === handler.get('input', 'Block') &&
367+
functionDeclaration.signature.parameters[0].type.name.next
368+
.next === null &&
369+
functionDeclaration.signature.returnType.name.identifier.text ===
370+
'void',
371+
),
372+
)
373+
? errors
374+
: errors.push(
375+
immutable.fromJS({
376+
path: [...path, index],
377+
message: `\
378+
Matching mapping handler not found in '${mappingFile}' for blockHandler: '${handler.get(
379+
'handler',
380+
)}'.
381+
Signature:
382+
${handler.get('handler')}(block: ethereum.${handler.get('input', 'Block')}): void`,
383+
}),
384+
),
385+
immutable.List(),
386+
),
387+
)
388+
}, immutable.List())
389+
}
390+
320391
static validateRepository(manifest, { resolveFile }) {
321392
return manifest.get('repository') !==
322393
'https://github.com/graphprotocol/example-subgraph'
@@ -446,6 +517,7 @@ More than one template named '${name}', template names must be unique.`,
446517
...Subgraph.validateEthereumContractHandlers(manifest),
447518
...Subgraph.validateEvents(manifest, { resolveFile }),
448519
...Subgraph.validateCallFunctions(manifest, { resolveFile }),
520+
...Subgraph.validateBlockFunctions(manifest, { resolveFile }),
449521
...Subgraph.validateUniqueDataSourceNames(manifest),
450522
...Subgraph.validateUniqueTemplateNames(manifest),
451523
)

0 commit comments

Comments
 (0)