jam_pvm_common/
result.rs

1use jam_types::{InvokeOutcomeCode, SimpleResult, SimpleResultCode, LOWEST_ERROR};
2
3/// Error type for host-calls.
4#[derive(Debug)]
5pub enum ApiError {
6	/// `OOB` Invalid memory access.
7	OutOfBounds,
8	/// `WHO` Target service is unknown.
9	IndexUnknown,
10	/// `FULL` Too much storage is used by the service for its holdings.
11	StorageFull,
12	/// `CORE` Bad core index given.
13	BadCore,
14	/// `CASH` The caller has too little funding.
15	NoCash,
16	/// `LOW` The gas limit provided is too low (lower than the amount of gas required for the
17	/// transfer).
18	GasLimitTooLow,
19	/// `HIGH` The gas limit provided is too high (higher than the amount of gas remaining).
20	GasLimitTooHigh,
21	/// `HUH` The hash is already solicited or forgotten.
22	ActionInvalid,
23}
24
25impl From<u64> for ApiError {
26	fn from(code: SimpleResult) -> Self {
27		match code {
28			c if c == SimpleResultCode::OutOfBounds as u64 => ApiError::OutOfBounds,
29			c if c == SimpleResultCode::IndexUnknown as u64 => ApiError::IndexUnknown,
30			c if c == SimpleResultCode::StorageFull as u64 => ApiError::StorageFull,
31			c if c == SimpleResultCode::BadCore as u64 => ApiError::BadCore,
32			c if c == SimpleResultCode::NoCash as u64 => ApiError::NoCash,
33			c if c == SimpleResultCode::GasLimitTooLow as u64 => ApiError::GasLimitTooLow,
34			c if c == SimpleResultCode::GasLimitTooHigh as u64 => ApiError::GasLimitTooHigh,
35			c if c == SimpleResultCode::ActionInvalid as u64 => ApiError::ActionInvalid,
36			_ => panic!("unknown error code: {}", code),
37		}
38	}
39}
40
41/// Result type for host-calls, parameterized by the type of the successful result.
42pub type ApiResult<T> = Result<T, ApiError>;
43
44/// Simple conversion trait for types which can be converted to a regular host-call API result.
45pub trait IntoApiResult<T> {
46	fn into_api_result(self) -> ApiResult<T>;
47}
48
49impl IntoApiResult<()> for SimpleResult {
50	fn into_api_result(self) -> ApiResult<()> {
51		if self == SimpleResultCode::Ok as u64 {
52			Ok(())
53		} else {
54			Err(self.into())
55		}
56	}
57}
58impl IntoApiResult<u64> for SimpleResult {
59	fn into_api_result(self) -> ApiResult<u64> {
60		if self < LOWEST_ERROR {
61			Ok(self)
62		} else {
63			Err(self.into())
64		}
65	}
66}
67impl IntoApiResult<u32> for SimpleResult {
68	fn into_api_result(self) -> ApiResult<u32> {
69		if self <= u32::MAX as _ {
70			Ok(self as u32)
71		} else if self < LOWEST_ERROR {
72			panic!("Our own API impl has resulted in success value which is out of range.");
73		} else {
74			Err(self.into())
75		}
76	}
77}
78impl IntoApiResult<Option<()>> for SimpleResult {
79	fn into_api_result(self) -> ApiResult<Option<()>> {
80		if self < LOWEST_ERROR {
81			Ok(Some(()))
82		} else if self == SimpleResultCode::Nothing as u64 {
83			Ok(None)
84		} else {
85			Err(self.into())
86		}
87	}
88}
89impl IntoApiResult<Option<u64>> for SimpleResult {
90	fn into_api_result(self) -> ApiResult<Option<u64>> {
91		if self < LOWEST_ERROR {
92			Ok(Some(self))
93		} else if self == SimpleResultCode::Nothing as u64 {
94			Ok(None)
95		} else {
96			Err(self.into())
97		}
98	}
99}
100
101/// The successful result of inner PVM invocations.
102pub enum InvokeOutcome {
103	/// `HALT` Completed normally.
104	Halt,
105	/// `FAULT` Completed with a page fault.
106	PageFault(u64),
107	/// `HOST` Completed with a host-call fault.
108	HostCallFault(u64),
109	/// `PANIC` Completed with a panic.
110	Panic,
111	/// `OOG` Completed by running out of gas.
112	OutOfGas,
113}
114
115/// The result of the [crate::refine::invoke] host-call.
116pub type InvokeResult = ApiResult<InvokeOutcome>;
117
118/// Simple trait to convert to `InvokeResult`.
119pub trait IntoInvokeResult {
120	/// Convert `self` to `InvokeResult`.
121	fn into_invoke_result(self) -> InvokeResult;
122}
123
124impl IntoInvokeResult for (u64, u64) {
125	fn into_invoke_result(self) -> InvokeResult {
126		const STATUS_HALT: u64 = InvokeOutcomeCode::Halt as u64;
127		const STATUS_PANIC: u64 = InvokeOutcomeCode::Panic as u64;
128		const STATUS_FAULT: u64 = InvokeOutcomeCode::PageFault as u64;
129		const STATUS_HOST: u64 = InvokeOutcomeCode::HostCallFault as u64;
130		const STATUS_OOG: u64 = InvokeOutcomeCode::OutOfGas as u64;
131		// Convert `invoke` return value to `Result`.
132		match self {
133			(STATUS_HALT, _) => Ok(InvokeOutcome::Halt),
134			(STATUS_FAULT, address) => Ok(InvokeOutcome::PageFault(address)),
135			(STATUS_HOST, index) => Ok(InvokeOutcome::HostCallFault(index)),
136			(STATUS_PANIC, _) => Ok(InvokeOutcome::Panic),
137			(STATUS_OOG, _) => Ok(InvokeOutcome::OutOfGas),
138			(code, _) => Err(code.into()),
139		}
140	}
141}