Skip to content

Commit d12d454

Browse files
committed
gnd: Validate WASM handler exports after compilation
After compiling AssemblyScript mappings to WASM, parse the compiled binary with wasmparser and verify that all handler names declared in the manifest (event, call, and block handlers) exist as exported functions. This catches mismatches between the manifest and the actual WASM code early, during `gnd build`, rather than at deployment time.
1 parent 2e253fb commit d12d454

4 files changed

Lines changed: 366 additions & 1 deletion

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gnd/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ semver = { workspace = true }
6363

6464
# Build command
6565
sha1 = "0.10"
66+
wasmparser = { workspace = true }
6667

6768
# Test command
6869
which = "7"

gnd/src/commands/build.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use crate::migrations;
2020
use crate::output::{step, Step};
2121
use crate::services::IpfsClient;
2222
use crate::validation::{
23-
format_manifest_errors, format_schema_errors, validate_manifest, validate_schema,
23+
collect_handler_names, collect_template_handler_names, format_manifest_errors,
24+
format_schema_errors, validate_manifest, validate_schema, validate_wasm_handlers,
2425
};
2526
use crate::watch::watch_and_run;
2627

@@ -234,6 +235,55 @@ async fn build_subgraph(opt: &BuildOpt) -> Result<BuildResult> {
234235
}
235236
}
236237

238+
// Validate compiled WASM handler exports (only for binary WASM output)
239+
if opt.output_format == "wasm" {
240+
let mut wasm_errors = Vec::new();
241+
242+
for ds in &manifest.data_sources {
243+
let handler_names = collect_handler_names(ds);
244+
if handler_names.is_empty() {
245+
continue;
246+
}
247+
let wasm_path = opt
248+
.output_dir
249+
.join(&ds.name)
250+
.join(format!("{}.wasm", ds.name));
251+
if wasm_path.exists() {
252+
wasm_errors.extend(validate_wasm_handlers(&wasm_path, &ds.name, &handler_names));
253+
}
254+
}
255+
256+
for template in &manifest.templates {
257+
let handler_names = collect_template_handler_names(template);
258+
if handler_names.is_empty() {
259+
continue;
260+
}
261+
let wasm_path = opt
262+
.output_dir
263+
.join("templates")
264+
.join(&template.name)
265+
.join(format!("{}.wasm", template.name));
266+
if wasm_path.exists() {
267+
wasm_errors.extend(validate_wasm_handlers(
268+
&wasm_path,
269+
&template.name,
270+
&handler_names,
271+
));
272+
}
273+
}
274+
275+
if !wasm_errors.is_empty() {
276+
eprintln!(
277+
"WASM handler validation errors:\n{}",
278+
format_manifest_errors(&wasm_errors)
279+
);
280+
return Err(anyhow!(
281+
"WASM handler validation failed with {} error(s)",
282+
wasm_errors.len()
283+
));
284+
}
285+
}
286+
237287
// Copy schema file
238288
if let Some(schema_path) = &manifest.schema {
239289
let schema_path = resolve_path(&opt.manifest, schema_path);

0 commit comments

Comments
 (0)