oasis_runtime_sdk_contracts/abi/oasis/
env.rs1use oasis_contract_sdk_types::{
3 env::{AccountsQuery, AccountsResponse, QueryRequest, QueryResponse},
4 InstanceId,
5};
6use oasis_runtime_sdk::{context::Context, modules::accounts::API as _, Runtime};
7
8use super::{memory::Region, OasisV1};
9use crate::{
10 abi::{gas, ExecutionContext},
11 types::Instance,
12 Config, Error,
13};
14
15impl<Cfg: Config> OasisV1<Cfg> {
16 pub fn link_env<C: Context>(
18 instance: &mut wasm3::Instance<'_, '_, ExecutionContext<'_, C>>,
19 ) -> Result<(), Error> {
20 let _ = instance.link_function(
22 "env",
23 "query",
24 |ctx, query: (u32, u32)| -> Result<u32, wasm3::Trap> {
25 let ec = ctx.context.ok_or(wasm3::Trap::Abort)?;
27
28 gas::use_gas(ctx.instance, ec.params.gas_costs.wasm_env_query_base)?;
30
31 let request: QueryRequest = ctx.instance.runtime().try_with_memory(
33 |memory| -> Result<_, wasm3::Trap> {
34 let query = Region::from_arg(query).as_slice(&memory)?;
35 if query.len() > ec.params.max_query_size_bytes as usize {
36 return Err(wasm3::Trap::Abort);
38 }
39
40 cbor::from_slice(query).map_err(|_| wasm3::Trap::Abort)
41 },
42 )??;
43
44 let result = dispatch_query::<C>(ec.tx_context, request);
46
47 Self::serialize_and_allocate_as_ptr(ctx.instance, result).map_err(|err| err.into())
52 },
53 );
54
55 let _ = instance.link_function(
57 "env",
58 "address_for_instance",
59 |ctx, request: (u64, (u32, u32))| -> Result<(), wasm3::Trap> {
60 let ec = ctx.context.ok_or(wasm3::Trap::Abort)?;
62
63 gas::use_gas(ctx.instance, ec.params.gas_costs.wasm_env_query_base)?;
66
67 ctx.instance
68 .runtime()
69 .try_with_memory(|mut memory| -> Result<_, wasm3::Trap> {
70 let instance_id: InstanceId = request.0.into();
71 let dst = Region::from_arg(request.1).as_slice_mut(&mut memory)?;
72
73 let address = Instance::address_for(instance_id);
74
75 dst.copy_from_slice(address.as_ref());
76
77 Ok(())
78 })?
79 },
80 );
81
82 #[cfg(feature = "debug-utils")]
84 let _ = instance.link_function(
85 "env",
86 "debug_print",
87 |ctx, request: (u32, u32)| -> Result<(), wasm3::Trap> {
88 ctx.instance
89 .runtime()
90 .try_with_memory(|memory| -> Result<_, wasm3::Trap> {
91 let msg_bytes = Region::from_arg(request).as_slice(&memory)?;
92 if let Ok(msg) = std::str::from_utf8(msg_bytes) {
93 eprintln!("{msg}");
94 }
95 Ok(())
96 })?
97 },
98 );
99
100 Ok(())
101 }
102}
103
104fn dispatch_query<C: Context>(ctx: &C, query: QueryRequest) -> QueryResponse {
106 match query {
107 QueryRequest::BlockInfo => QueryResponse::BlockInfo {
109 round: ctx.runtime_header().round,
110 epoch: ctx.epoch(),
111 timestamp: ctx.runtime_header().timestamp,
112 },
113
114 QueryRequest::Accounts(query) => dispatch_accounts_query::<C>(ctx, query),
116
117 _ => QueryResponse::Error {
118 module: "".to_string(),
119 code: 1,
120 message: "query not supported".to_string(),
121 },
122 }
123}
124
125fn dispatch_accounts_query<C: Context>(_ctx: &C, query: AccountsQuery) -> QueryResponse {
127 match query {
128 AccountsQuery::Balance {
129 address,
130 denomination,
131 } => {
132 let balance =
133 <C::Runtime as Runtime>::Accounts::get_balance(address.into(), denomination.into())
134 .unwrap_or_default();
135
136 AccountsResponse::Balance { balance }.into()
137 }
138
139 _ => QueryResponse::Error {
140 module: "".to_string(),
141 code: 1,
142 message: "query not supported".to_string(),
143 },
144 }
145}