gear_core_backend/
lib.rs

1// This file is part of Gear.
2
3// Copyright (C) 2021-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Provide sp-sandbox support.
20
21#![cfg_attr(not(feature = "std"), no_std)]
22
23extern crate alloc;
24
25mod accessors;
26pub mod env;
27pub mod error;
28mod funcs;
29mod log;
30pub mod memory;
31#[cfg(any(feature = "mock", test))]
32pub mod mock;
33mod runtime;
34pub mod state;
35
36use gear_core::{
37    env::Externalities,
38    gas::{CountersOwner, GasAmount},
39    memory::MemoryInterval,
40};
41use gear_lazy_pages_common::ProcessAccessError;
42
43/// Extended externalities that can manage gas counters.
44pub trait BackendExternalities: Externalities + CountersOwner {
45    fn gas_amount(&self) -> GasAmount;
46
47    /// Pre-process memory access if needed.
48    fn pre_process_memory_accesses(
49        &mut self,
50        reads: &[MemoryInterval],
51        writes: &[MemoryInterval],
52        gas_counter: &mut u64,
53    ) -> Result<(), ProcessAccessError>;
54}
55
56#[cfg(test)]
57mod tests {
58    use crate::{
59        env::{BackendReport, Environment},
60        error::ActorTerminationReason,
61        mock::MockExt,
62    };
63    use gear_core::{gas_metering::CustomConstantCostRules, message::DispatchKind};
64    use gear_wasm_instrument::{
65        FuncType, Function, Import, InstrumentationBuilder, ModuleBuilder, SyscallName,
66    };
67    use tracing_subscriber::EnvFilter;
68
69    /// Check that all syscalls are supported by backend.
70    #[test]
71    fn test_syscalls_table() {
72        tracing_subscriber::fmt::fmt()
73            .with_env_filter(EnvFilter::from_default_env())
74            .with_test_writer()
75            .init();
76
77        // Make module with one empty function.
78        let mut module = ModuleBuilder::default();
79        module.add_func(FuncType::new([], []), Function::default());
80
81        // Insert syscalls imports.
82        for name in SyscallName::instrumentable() {
83            let sign = name.signature();
84            let type_no = module.push_type(sign.func_type());
85
86            module.push_import(Import::func("env", name.to_str(), type_no));
87        }
88
89        let module = InstrumentationBuilder::new("env")
90            .with_gas_limiter(|_| CustomConstantCostRules::default())
91            .instrument(module.build())
92            .unwrap();
93        let code = module.serialize().unwrap();
94
95        // Execute wasm and check success.
96        let ext = MockExt::default();
97        let env =
98            Environment::new(ext, &code, DispatchKind::Init, Default::default(), 0.into()).unwrap();
99        let report = env.execute(|_, _, _| {}).unwrap();
100
101        let BackendReport {
102            termination_reason, ..
103        } = report;
104
105        assert_eq!(termination_reason, ActorTerminationReason::Success.into());
106    }
107}