diff --git a/runtime/test/src/test/abi.rs b/runtime/test/src/test/abi.rs index 43cda3ccdac..3c7c2ea13f4 100644 --- a/runtime/test/src/test/abi.rs +++ b/runtime/test/src/test/abi.rs @@ -1,10 +1,6 @@ use graph::prelude::{ethabi::Token, web3::types::U256}; -use graph_runtime_wasm::{ - asc_abi::class::{ - ArrayBuffer, AscAddress, AscEnum, AscEnumArray, EthereumValueKind, StoreValueKind, - TypedArray, - }, - TRAP_TIMEOUT, +use graph_runtime_wasm::asc_abi::class::{ + ArrayBuffer, AscAddress, AscEnum, AscEnumArray, EthereumValueKind, StoreValueKind, TypedArray, }; use super::*; @@ -23,7 +19,10 @@ async fn test_unbounded_loop(api_version: Version) { .await .0; let res: Result<(), _> = module.get_func("loop").typed().unwrap().call(()); - assert!(res.unwrap_err().to_string().contains(TRAP_TIMEOUT)); + assert_eq!( + res.unwrap_err().to_string().lines().next().unwrap(), + "wasm trap: interrupt" + ); } #[tokio::test(flavor = "multi_thread")] diff --git a/runtime/wasm/src/lib.rs b/runtime/wasm/src/lib.rs index 2a365b9468f..a9b28f872f1 100644 --- a/runtime/wasm/src/lib.rs +++ b/runtime/wasm/src/lib.rs @@ -21,6 +21,3 @@ pub use host::RuntimeHostBuilder; pub use host_exports::HostExports; pub use mapping::{MappingContext, ValidModule}; pub use module::{ExperimentalFeatures, WasmInstance}; - -#[cfg(debug_assertions)] -pub use module::TRAP_TIMEOUT; diff --git a/runtime/wasm/src/module/mod.rs b/runtime/wasm/src/module/mod.rs index 85aa8c151aa..ee17e5b5533 100644 --- a/runtime/wasm/src/module/mod.rs +++ b/runtime/wasm/src/module/mod.rs @@ -14,7 +14,7 @@ use graph::data::value::Word; use graph::slog::SendSyncRefUnwindSafeKV; use never::Never; use semver::Version; -use wasmtime::{Memory, Trap}; +use wasmtime::{Memory, Trap, TrapCode}; use graph::blockchain::{Blockchain, HostFnCtx}; use graph::data::store; @@ -43,8 +43,6 @@ use crate::mapping::ValidModule; mod into_wasm_ret; pub mod stopwatch; -pub const TRAP_TIMEOUT: &str = "trap: interrupt"; - // Convenience for a 'top-level' asc_get, with depth 0. fn asc_get( heap: &H, @@ -266,8 +264,14 @@ impl WasmInstance { return Err(MappingError::PossibleReorg(trap.into())); } - // Treat as a special case to have a better error message. - Err(trap) if trap.to_string().contains(TRAP_TIMEOUT) => { + // Treat timeouts anywhere in the error chain as a special case to have a better error + // message. Any `TrapCode::Interrupt` is assumed to be a timeout. + Err(trap) + if Error::from(trap.clone()).chain().any(|e| { + e.downcast_ref::().and_then(|t| t.trap_code()) + == Some(TrapCode::Interrupt) + }) => + { self.instance_ctx_mut().ctx.state.exit_handler(); return Err(MappingError::Unknown(Error::from(trap).context(format!( "Handler '{}' hit the timeout of '{}' seconds", @@ -280,7 +284,7 @@ impl WasmInstance { is_trap_deterministic(&trap) || self.instance_ctx().deterministic_host_trap; let e = Error::from(trap); match trap_is_deterministic { - true => Some(Error::from(e)), + true => Some(e), false => { self.instance_ctx_mut().ctx.state.exit_handler(); return Err(MappingError::Unknown(e));