Skip to main content

corevm_engine/
error.rs

1use corevm_host::{fs, Outcome, PageNum};
2use jam_pvm_common::ApiError;
3
4/// Engine initialization error.
5#[derive(thiserror::Error, Debug)]
6pub enum InitError {
7	#[error("JAM error: {0:?}")]
8	Jam(ApiError),
9	#[error("CoreVM FS error: {0:?}")]
10	Fs(fs::Error),
11	#[error("Invalid program blob")]
12	ProgramBlob,
13	#[error("Invalid exec blob")]
14	ExecBlob,
15	#[error("None or both `main` and `_pvm_start` entry points were found")]
16	EntryPoint,
17	#[error("Invalid memory page was imported into the package")]
18	InvalidPage,
19	#[error("Input limit reached while initializing the engine")]
20	InputLimitReached,
21}
22
23impl From<polkavm::program::ProgramParseError> for InitError {
24	fn from(_: polkavm::program::ProgramParseError) -> Self {
25		Self::ProgramBlob
26	}
27}
28
29impl From<ApiError> for InitError {
30	fn from(e: ApiError) -> Self {
31		Self::Jam(e)
32	}
33}
34
35impl From<fs::Error> for InitError {
36	fn from(e: fs::Error) -> Self {
37		Self::Fs(e)
38	}
39}
40
41/// Fatal engine error after which the continuation is not possible.
42#[derive(thiserror::Error, Debug)]
43pub enum FatalError {
44	#[error("Input space limit reached while restarting a host-call")]
45	NotEnoughInputSpace,
46	#[error("Output space limit reached while restarting a host-call")]
47	NotEnoughOutputSpace,
48	#[error("Unknown host-call")]
49	UnknownHostCall,
50	#[error("Guest attempted to read/write reserved/unmapped memory address")]
51	InvalidMemoryAccess,
52}
53
54/// Engine runtime error.
55#[derive(thiserror::Error, Debug)]
56pub enum RunError {
57	#[error("JAM error: {0:?}")]
58	Jam(ApiError),
59	#[error("CoreVM FS error: {0:?}")]
60	Fs(fs::Error),
61	#[error("Fatal error: {0:?}")]
62	Fatal(FatalError),
63	#[error("Failed to initialize libc")]
64	LibcInit,
65}
66
67impl From<ApiError> for RunError {
68	fn from(e: ApiError) -> Self {
69		Self::Jam(e)
70	}
71}
72
73impl From<fs::Error> for RunError {
74	fn from(e: fs::Error) -> Self {
75		Self::Fs(e)
76	}
77}
78
79impl From<FatalError> for RunError {
80	fn from(e: FatalError) -> Self {
81		Self::Fatal(e)
82	}
83}
84
85#[derive(Debug)]
86pub(crate) enum HostCallError {
87	Jam(ApiError),
88	Fs(fs::Error),
89	Outcome(Outcome),
90	Fatal(FatalError),
91}
92
93impl From<Outcome> for HostCallError {
94	fn from(outcome: Outcome) -> Self {
95		Self::Outcome(outcome)
96	}
97}
98
99impl From<TimeLimitReached> for HostCallError {
100	fn from(_: TimeLimitReached) -> Self {
101		Self::Outcome(Outcome::TimeLimitReached)
102	}
103}
104
105impl From<OutputLimitReached> for HostCallError {
106	fn from(_: OutputLimitReached) -> Self {
107		Self::Outcome(Outcome::OutputLimitReached)
108	}
109}
110
111impl From<InputLimitReached> for HostCallError {
112	fn from(_: InputLimitReached) -> Self {
113		Self::Outcome(Outcome::InputLimitReached)
114	}
115}
116
117impl From<ApiError> for HostCallError {
118	fn from(e: ApiError) -> Self {
119		Self::Jam(e)
120	}
121}
122
123impl From<fs::Error> for HostCallError {
124	fn from(e: fs::Error) -> Self {
125		Self::Fs(e)
126	}
127}
128
129impl From<FatalError> for HostCallError {
130	fn from(e: FatalError) -> Self {
131		Self::Fatal(e)
132	}
133}
134
135impl From<TouchError> for HostCallError {
136	fn from(e: TouchError) -> Self {
137		match e {
138			TouchError::PageFault { page, num_pages } =>
139				Self::Outcome(Outcome::PageFault { page, num_pages }),
140			TouchError::Jam(e) => Self::Jam(e),
141			TouchError::InvalidMemoryAccess => Self::Fatal(FatalError::InvalidMemoryAccess),
142			TouchError::InputLimitReached => Self::Outcome(Outcome::InputLimitReached),
143		}
144	}
145}
146
147impl From<polkakernel::MachineError> for HostCallError {
148	fn from(e: polkakernel::MachineError) -> Self {
149		match e {
150			polkakernel::MachineError::BadAddress => Self::Fatal(FatalError::InvalidMemoryAccess),
151		}
152	}
153}
154
155impl From<TooLargeWorkOutput> for HostCallError {
156	fn from(_: TooLargeWorkOutput) -> Self {
157		Self::Outcome(Outcome::OutputLimitReached)
158	}
159}
160
161#[derive(Debug)]
162pub(crate) enum TouchError {
163	PageFault { page: PageNum, num_pages: u32 },
164	Jam(ApiError),
165	InvalidMemoryAccess,
166	InputLimitReached,
167}
168
169impl From<ApiError> for TouchError {
170	fn from(e: ApiError) -> Self {
171		Self::Jam(e)
172	}
173}
174
175impl From<InputLimitReached> for TouchError {
176	fn from(_: InputLimitReached) -> Self {
177		Self::InputLimitReached
178	}
179}
180
181/// The guest produced/consumed one time-slot worth of video frames and audio samples.
182#[derive(Debug)]
183pub(crate) struct TimeLimitReached;
184
185/// The guest produced `WorkItem::export_count` worth of export segments.
186///
187/// These include updated memory pages, video/audio/console output and page map.
188#[derive(Debug)]
189pub(crate) struct OutputLimitReached;
190
191/// Max. work output size exceeded.
192#[derive(Debug)]
193pub(crate) struct TooLargeWorkOutput;
194
195/// The guest reached [`max_input`](jam_types::max_input) input size.
196///
197/// This can happen on page import or while reading input stream or receiving a message.
198/// This error is only used in the simulator and should never occur on JAM node.
199#[derive(Debug)]
200pub(crate) struct InputLimitReached;