oasis_runtime_sdk_contracts/
lib.rs

1//! Smart contracts module.
2#![deny(rust_2018_idioms)]
3#![forbid(unsafe_code)]
4#![cfg_attr(all(feature = "benchmarks", test), feature(test))]
5
6#[cfg(test)]
7extern crate alloc;
8
9use std::{convert::TryInto, io::Read};
10
11use thiserror::Error;
12
13use oasis_contract_sdk_types::storage::StoreKind;
14use oasis_runtime_sdk::{
15    self as sdk,
16    context::Context,
17    core::common::crypto::hash::Hash,
18    handler, migration, module,
19    module::Module as _,
20    modules,
21    modules::{accounts::API as _, core::API as _},
22    runtime::Runtime,
23    sdk_derive,
24    state::CurrentState,
25    storage,
26    storage::Store,
27    types::transaction::CallFormat,
28};
29
30use crate::store::with_instance_raw_store;
31
32mod abi;
33mod code;
34mod results;
35mod store;
36#[cfg(test)]
37mod test;
38pub mod types;
39mod wasm;
40
41/// Unique module name.
42const MODULE_NAME: &str = "contracts";
43
44/// Errors emitted by the contracts module.
45#[derive(Error, Debug, sdk::Error)]
46pub enum Error {
47    #[error("invalid argument")]
48    #[sdk_error(code = 1)]
49    InvalidArgument,
50
51    #[error("code too large (size: {0} max: {1})")]
52    #[sdk_error(code = 2)]
53    CodeTooLarge(u32, u32),
54
55    #[error("code is malformed")]
56    #[sdk_error(code = 3)]
57    CodeMalformed,
58
59    #[error("specified ABI is not supported")]
60    #[sdk_error(code = 4)]
61    UnsupportedABI,
62
63    #[error("code is missing required ABI export: {0}")]
64    #[sdk_error(code = 5)]
65    CodeMissingRequiredExport(String),
66
67    #[error("code declares reserved ABI export: {0}")]
68    #[sdk_error(code = 6)]
69    CodeDeclaresReservedExport(String),
70
71    #[error("code declares start function")]
72    #[sdk_error(code = 7)]
73    CodeDeclaresStartFunction,
74
75    #[error("code declares too many memories")]
76    #[sdk_error(code = 8)]
77    CodeDeclaresTooManyMemories,
78
79    #[error("code {0} not found")]
80    #[sdk_error(code = 9)]
81    CodeNotFound(u64),
82
83    #[error("instance {0} not found")]
84    #[sdk_error(code = 10)]
85    InstanceNotFound(u64),
86
87    #[error("module loading failed")]
88    #[sdk_error(code = 11)]
89    ModuleLoadingFailed,
90
91    #[error("execution failed: {0}")]
92    #[sdk_error(code = 12)]
93    ExecutionFailed(#[source] anyhow::Error),
94
95    #[error("forbidden by policy")]
96    #[sdk_error(code = 13)]
97    Forbidden,
98
99    #[error("function not supported")]
100    #[sdk_error(code = 14)]
101    Unsupported,
102
103    #[error("insufficient balance in caller account")]
104    #[sdk_error(code = 15)]
105    InsufficientCallerBalance,
106
107    // Error code 16 is reserved.
108    #[error("result size exceeded (size: {0} max: {1})")]
109    #[sdk_error(code = 17)]
110    ResultTooLarge(u32, u32),
111
112    #[error("too many subcalls (count: {0} max: {1})")]
113    #[sdk_error(code = 18)]
114    TooManySubcalls(u16, u16),
115
116    #[error("instance is already using code {0}")]
117    #[sdk_error(code = 19)]
118    CodeAlreadyUpgraded(u64),
119
120    #[error("abort: {0}")]
121    #[sdk_error(code = 20, abort)]
122    Abort(#[from] sdk::dispatcher::Error),
123
124    #[error("storage: key too large (size: {0} max: {1})")]
125    #[sdk_error(code = 21)]
126    StorageKeyTooLarge(u32, u32),
127
128    #[error("storage: value too large (size: {0} max: {1})")]
129    #[sdk_error(code = 22)]
130    StorageValueTooLarge(u32, u32),
131
132    #[error("crypto: msg too large (size: {0} max: {1})")]
133    #[sdk_error(code = 23)]
134    CryptoMsgTooLarge(u32, u32),
135
136    #[error("crypto: malformed public key")]
137    #[sdk_error(code = 24)]
138    CryptoMalformedPublicKey,
139
140    #[error("code declares multiple sub-versions")]
141    #[sdk_error(code = 25)]
142    CodeDeclaresMultipleSubVersions,
143
144    #[error("crypto: malformed private key")]
145    #[sdk_error(code = 26)]
146    CryptoMalformedPrivateKey,
147
148    #[error("crypto: malformed encryption key")]
149    #[sdk_error(code = 27)]
150    CryptoMalformedKey,
151
152    #[error("crypto: malformed nonce")]
153    #[sdk_error(code = 28)]
154    CryptoMalformedNonce,
155
156    #[error("crypto: key derivation function failure")]
157    #[sdk_error(code = 29)]
158    CryptoKeyDerivationFunctionFailure,
159
160    #[error("module uses floating point data or operations")]
161    #[sdk_error(code = 30)]
162    ModuleUsesFloatingPoint,
163
164    #[error("code declares too many functions")]
165    #[sdk_error(code = 31)]
166    CodeDeclaresTooManyFunctions,
167
168    #[error("code declares too many locals")]
169    #[sdk_error(code = 32)]
170    CodeDeclaresTooManyLocals,
171
172    #[error("core: {0}")]
173    #[sdk_error(transparent)]
174    Core(#[from] modules::core::Error),
175
176    #[error("contract error: {0}")]
177    #[sdk_error(transparent)]
178    Contract(#[from] wasm::ContractError),
179}
180
181/// Events emitted by the contracts module.
182#[derive(Debug, cbor::Encode, sdk::Event)]
183#[cbor(untagged)]
184pub enum Event {}
185
186/// Gas costs.
187#[derive(Clone, Debug, cbor::Encode, cbor::Decode)]
188pub struct GasCosts {
189    pub tx_upload: u64,
190    pub tx_upload_per_byte: u64,
191    pub tx_instantiate: u64,
192    pub tx_call: u64,
193    pub tx_upgrade: u64,
194    pub tx_change_upgrade_policy: u64,
195
196    // Subcalls.
197    pub subcall_dispatch: u64,
198
199    // Storage operations.
200    pub wasm_public_storage_get_base: u64,
201    pub wasm_public_storage_insert_base: u64,
202    pub wasm_public_storage_remove_base: u64,
203    pub wasm_public_storage_key_byte: u64,
204    pub wasm_public_storage_value_byte: u64,
205    pub wasm_confidential_storage_get_base: u64,
206    pub wasm_confidential_storage_insert_base: u64,
207    pub wasm_confidential_storage_remove_base: u64,
208    pub wasm_confidential_storage_key_byte: u64,
209    pub wasm_confidential_storage_value_byte: u64,
210    pub wasm_env_query_base: u64,
211
212    // Crypto operations.
213    pub wasm_crypto_ecdsa_recover: u64,
214    pub wasm_crypto_signature_verify_ed25519: u64,
215    pub wasm_crypto_signature_verify_secp256k1: u64,
216    pub wasm_crypto_signature_verify_sr25519: u64,
217    pub wasm_crypto_x25519_derive_symmetric: u64,
218    pub wasm_crypto_deoxysii_base: u64,
219    pub wasm_crypto_deoxysii_byte: u64,
220    pub wasm_crypto_random_bytes_base: u64,
221    pub wasm_crypto_random_bytes_byte: u64,
222}
223
224impl Default for GasCosts {
225    fn default() -> Self {
226        // The below assume a batch gas limit of 1_000_000_000 ~ 1s.
227        GasCosts {
228            tx_upload: 30_000_000,
229            tx_upload_per_byte: 400,
230            tx_instantiate: 100_000,
231            tx_call: 50_000,
232            tx_upgrade: 50_000,
233            tx_change_upgrade_policy: 30_000,
234
235            subcall_dispatch: 1_000,
236
237            wasm_public_storage_get_base: 5_000,
238            wasm_public_storage_insert_base: 8_400,
239            wasm_public_storage_remove_base: 6_400,
240            wasm_public_storage_key_byte: 3_000,
241            wasm_public_storage_value_byte: 300,
242            wasm_confidential_storage_get_base: 10_000,
243            wasm_confidential_storage_insert_base: 16_800,
244            wasm_confidential_storage_remove_base: 12_800,
245            wasm_confidential_storage_key_byte: 3_500,
246            wasm_confidential_storage_value_byte: 400,
247            wasm_env_query_base: 100,
248
249            wasm_crypto_ecdsa_recover: 500_000,
250            wasm_crypto_signature_verify_ed25519: 500_000,
251            wasm_crypto_signature_verify_secp256k1: 500_000,
252            wasm_crypto_signature_verify_sr25519: 500_000,
253            wasm_crypto_x25519_derive_symmetric: 250_000,
254            wasm_crypto_deoxysii_base: 1_000,
255            wasm_crypto_deoxysii_byte: 3,
256            wasm_crypto_random_bytes_base: 1_000,
257            wasm_crypto_random_bytes_byte: 3,
258        }
259    }
260}
261
262/// Parameters for the contracts module.
263#[derive(Clone, Debug, cbor::Encode, cbor::Decode)]
264pub struct Parameters {
265    pub max_code_size: u32,
266    pub max_stack_size: u32,
267    pub max_memory_pages: u32,
268
269    pub max_wasm_functions: u32,
270    pub max_wasm_locals: u32,
271
272    pub max_subcall_depth: u16,
273    pub max_subcall_count: u16,
274
275    pub max_result_size_bytes: u32,
276    pub max_query_size_bytes: u32,
277    pub max_storage_key_size_bytes: u32,
278    pub max_storage_value_size_bytes: u32,
279    pub max_crypto_signature_verify_message_size_bytes: u32,
280
281    pub gas_costs: GasCosts,
282}
283
284impl Default for Parameters {
285    fn default() -> Self {
286        Parameters {
287            max_code_size: 1024 * 1024, // 1 MiB
288            max_stack_size: 60 * 1024,  // 60 KiB
289            max_memory_pages: 160,      // 10 MiB
290
291            max_wasm_functions: 10_000,
292            max_wasm_locals: 256_000,
293
294            max_subcall_depth: 8,
295            max_subcall_count: 16,
296
297            max_result_size_bytes: 1024, // 1 KiB
298            max_query_size_bytes: 1024,  // 1 KiB
299            max_storage_key_size_bytes: 64,
300            max_storage_value_size_bytes: 16 * 1024, // 16 KiB
301            max_crypto_signature_verify_message_size_bytes: 16 * 1024, // 16KiB
302
303            gas_costs: Default::default(),
304        }
305    }
306}
307
308impl module::Parameters for Parameters {
309    type Error = std::convert::Infallible;
310}
311
312/// Genesis state for the contracts module.
313#[derive(Clone, Debug, Default, cbor::Encode, cbor::Decode)]
314pub struct Genesis {
315    pub parameters: Parameters,
316}
317
318/// Local configuration that can be provided by the node operator.
319#[derive(Clone, Debug, cbor::Encode, cbor::Decode)]
320pub struct LocalConfig {
321    /// Gas limit for custom queries that invoke smart contracts.
322    #[cbor(optional)]
323    pub query_custom_max_gas: u64,
324
325    /// Maximum number of items per page in InstanceRawStorage query result.
326    #[cbor(optional)]
327    pub max_instance_raw_storage_query_items: u64,
328}
329
330impl Default for LocalConfig {
331    fn default() -> Self {
332        Self {
333            query_custom_max_gas: 10_000_000,
334            max_instance_raw_storage_query_items: 100,
335        }
336    }
337}
338
339/// State schema constants.
340pub mod state {
341    /// Next code identifier (u64).
342    pub const NEXT_CODE_IDENTIFIER: &[u8] = &[0x01];
343    /// Next instance identifier (u64).
344    pub const NEXT_INSTANCE_IDENTIFIER: &[u8] = &[0x02];
345    /// Information about uploaded code.
346    pub const CODE_INFO: &[u8] = &[0x03];
347    /// Information about the deployed contract instance.
348    pub const INSTANCE_INFO: &[u8] = &[0x04];
349    /// Per-instance key/value store.
350    pub const INSTANCE_STATE: &[u8] = &[0x05];
351
352    /// Uploaded code.
353    pub const CODE: &[u8] = &[0xFF];
354}
355
356/// Module configuration.
357pub trait Config: 'static {}
358
359pub struct Module<Cfg: Config> {
360    _cfg: std::marker::PhantomData<Cfg>,
361}
362
363impl<Cfg: Config> Module<Cfg> {
364    /// Loads code information for the specified code identifier.
365    fn load_code_info(code_id: types::CodeId) -> Result<types::Code, Error> {
366        CurrentState::with_store(|store| {
367            let mut store = storage::PrefixStore::new(store, &MODULE_NAME);
368            let code_info_store =
369                storage::TypedStore::new(storage::PrefixStore::new(&mut store, &state::CODE_INFO));
370            let code_info = code_info_store
371                .get(code_id.to_storage_key())
372                .ok_or_else(|| Error::CodeNotFound(code_id.as_u64()))?;
373
374            Ok(code_info)
375        })
376    }
377
378    /// Stores specified code information.
379    fn store_code_info(code_info: types::Code) -> Result<(), Error> {
380        CurrentState::with_store(|store| {
381            let mut store = storage::PrefixStore::new(store, &MODULE_NAME);
382            let mut code_info_store =
383                storage::TypedStore::new(storage::PrefixStore::new(&mut store, &state::CODE_INFO));
384            code_info_store.insert(code_info.id.to_storage_key(), code_info);
385
386            Ok(())
387        })
388    }
389
390    /// Loads specified instance information.
391    fn load_instance_info(instance_id: types::InstanceId) -> Result<types::Instance, Error> {
392        CurrentState::with_store(|store| {
393            let mut store = storage::PrefixStore::new(store, &MODULE_NAME);
394            let instance_info_store = storage::TypedStore::new(storage::PrefixStore::new(
395                &mut store,
396                &state::INSTANCE_INFO,
397            ));
398            let instance_info = instance_info_store
399                .get(instance_id.to_storage_key())
400                .ok_or_else(|| Error::InstanceNotFound(instance_id.as_u64()))?;
401
402            Ok(instance_info)
403        })
404    }
405
406    /// Stores specified instance information.
407    fn store_instance_info(instance_info: types::Instance) -> Result<(), Error> {
408        CurrentState::with_store(|store| {
409            let mut store = storage::PrefixStore::new(store, &MODULE_NAME);
410            let mut instance_info_store = storage::TypedStore::new(storage::PrefixStore::new(
411                &mut store,
412                &state::INSTANCE_INFO,
413            ));
414            instance_info_store.insert(instance_info.id.to_storage_key(), instance_info);
415
416            Ok(())
417        })
418    }
419}
420
421#[sdk_derive(Module)]
422impl<Cfg: Config> Module<Cfg> {
423    const NAME: &'static str = MODULE_NAME;
424    type Error = Error;
425    type Event = Event;
426    type Parameters = Parameters;
427    type Genesis = Genesis;
428
429    #[migration(init)]
430    fn init(genesis: Genesis) {
431        // Set genesis parameters.
432        Self::set_params(genesis.parameters);
433    }
434
435    #[handler(call = "contracts.Upload")]
436    pub fn tx_upload<C: Context>(
437        ctx: &C,
438        body: types::Upload,
439    ) -> Result<types::UploadResult, Error> {
440        let params = Self::params();
441        let uploader = CurrentState::with_env(|env| env.tx_caller_address());
442
443        // Validate code size.
444        let code_size: u32 = body
445            .code
446            .len()
447            .try_into()
448            .map_err(|_| Error::CodeTooLarge(u32::MAX, params.max_code_size))?;
449        if code_size > params.max_code_size {
450            return Err(Error::CodeTooLarge(code_size, params.max_code_size));
451        }
452
453        // Account for base gas.
454        <C::Runtime as Runtime>::Core::use_tx_gas(params.gas_costs.tx_upload)?;
455        <C::Runtime as Runtime>::Core::use_tx_gas(
456            params
457                .gas_costs
458                .tx_upload_per_byte
459                .saturating_mul(body.code.len() as u64),
460        )?;
461
462        // Decompress code.
463        let mut code = Vec::with_capacity(body.code.len());
464        let decoder = snap::read::FrameDecoder::new(body.code.as_slice());
465        decoder
466            .take(params.max_code_size.into())
467            .read_to_end(&mut code)
468            .map_err(|_| Error::CodeMalformed)?;
469
470        // Account for extra gas needed after decompression.
471        let plain_code_size: u32 = code.len().try_into().unwrap();
472        <C::Runtime as Runtime>::Core::use_tx_gas(
473            params
474                .gas_costs
475                .tx_upload_per_byte
476                .saturating_mul(plain_code_size.saturating_sub(code_size) as u64),
477        )?;
478
479        if !ctx.should_execute_contracts() {
480            // Only fast checks are allowed.
481            return Ok(types::UploadResult::default());
482        }
483
484        // Validate and transform the code.
485        let (code, abi_info) = wasm::validate_and_transform::<Cfg, C>(&code, body.abi, &params)?;
486        let hash = Hash::digest_bytes(&code);
487
488        // Validate code size again and account for any instrumentation. This is here to avoid any
489        // incentives in generating code that gets maximally inflated after instrumentation.
490        let inst_code_size: u32 = code
491            .len()
492            .try_into()
493            .map_err(|_| Error::CodeTooLarge(u32::MAX, params.max_code_size))?;
494        if inst_code_size > params.max_code_size {
495            return Err(Error::CodeTooLarge(inst_code_size, params.max_code_size));
496        }
497        <C::Runtime as Runtime>::Core::use_tx_gas(
498            params
499                .gas_costs
500                .tx_upload_per_byte
501                .saturating_mul(inst_code_size.saturating_sub(plain_code_size) as u64),
502        )?;
503
504        // Assign next identifier.
505        let id = CurrentState::with_store(|store| {
506            let mut store = storage::PrefixStore::new(store, &MODULE_NAME);
507            let mut tstore = storage::TypedStore::new(&mut store);
508            let id: types::CodeId = tstore.get(state::NEXT_CODE_IDENTIFIER).unwrap_or_default();
509            tstore.insert(state::NEXT_CODE_IDENTIFIER, id.increment());
510            id
511        });
512
513        // Store information about uploaded code.
514        let code_info = types::Code {
515            id,
516            hash,
517            abi: body.abi,
518            abi_sv: abi_info.abi_sv,
519            uploader,
520            instantiate_policy: body.instantiate_policy,
521        };
522        Self::store_code(&code_info, &code)?;
523        Self::store_code_info(code_info)?;
524
525        Ok(types::UploadResult { id })
526    }
527
528    #[handler(call = "contracts.Instantiate")]
529    pub fn tx_instantiate<C: Context>(
530        ctx: &C,
531        body: types::Instantiate,
532    ) -> Result<types::InstantiateResult, Error> {
533        let params = Self::params();
534        let creator = CurrentState::with_env(|env| env.tx_caller_address());
535
536        <C::Runtime as Runtime>::Core::use_tx_gas(params.gas_costs.tx_instantiate)?;
537
538        if !ctx.should_execute_contracts() {
539            // Only fast checks are allowed.
540            return Ok(types::InstantiateResult::default());
541        }
542
543        // Load code information, enforce instantiation policy and load the code.
544        let code_info = Self::load_code_info(body.code_id)?;
545        code_info.instantiate_policy.enforce(&creator)?;
546        let code = Self::load_code(&code_info)?;
547
548        // Assign next identifier.
549        let id = CurrentState::with_store(|store| {
550            let mut store = storage::PrefixStore::new(store, &MODULE_NAME);
551            let mut tstore = storage::TypedStore::new(&mut store);
552            let id: types::InstanceId = tstore
553                .get(state::NEXT_INSTANCE_IDENTIFIER)
554                .unwrap_or_default();
555            tstore.insert(state::NEXT_INSTANCE_IDENTIFIER, id.increment());
556            id
557        });
558
559        // Store instance information.
560        let instance_info = types::Instance {
561            id,
562            code_id: body.code_id,
563            creator,
564            upgrades_policy: body.upgrades_policy,
565        };
566        Self::store_instance_info(instance_info.clone())?;
567
568        // Transfer any attached tokens.
569        for tokens in &body.tokens {
570            <C::Runtime as Runtime>::Accounts::transfer(creator, instance_info.address(), tokens)
571                .map_err(|_| Error::InsufficientCallerBalance)?
572        }
573        // Run instantiation function.
574        let contract = wasm::Contract {
575            code_info: &code_info,
576            code: &code,
577            instance_info: &instance_info,
578        };
579        let mut exec_ctx = abi::ExecutionContext::new(
580            &params,
581            &code_info,
582            &instance_info,
583            <C::Runtime as Runtime>::Core::remaining_tx_gas(),
584            creator,
585            CurrentState::with_env(|env| env.is_read_only()),
586            CurrentState::with_env(|env| env.tx_call_format()),
587            ctx,
588        );
589        let result = wasm::instantiate::<Cfg, C>(&mut exec_ctx, &contract, &body);
590
591        let result = results::process_execution_result(ctx, result)?;
592        results::process_execution_success::<Cfg, C>(ctx, &params, &contract, result)?;
593        Ok(types::InstantiateResult { id })
594    }
595
596    #[handler(call = "contracts.Call", allow_interactive)]
597    pub fn tx_call<C: Context>(ctx: &C, body: types::Call) -> Result<types::CallResult, Error> {
598        let params = Self::params();
599        let caller = CurrentState::with_env(|env| env.tx_caller_address());
600
601        <C::Runtime as Runtime>::Core::use_tx_gas(params.gas_costs.tx_call)?;
602
603        if !ctx.should_execute_contracts() {
604            // Only fast checks are allowed.
605            return Ok(types::CallResult::default());
606        }
607
608        // Load instance information and code.
609        let instance_info = Self::load_instance_info(body.id)?;
610        let code_info = Self::load_code_info(instance_info.code_id)?;
611        let code = Self::load_code(&code_info)?;
612
613        // Transfer any attached tokens.
614        for tokens in &body.tokens {
615            <C::Runtime as Runtime>::Accounts::transfer(caller, instance_info.address(), tokens)
616                .map_err(|_| Error::InsufficientCallerBalance)?
617        }
618        // Run call function.
619        let contract = wasm::Contract {
620            code_info: &code_info,
621            code: &code,
622            instance_info: &instance_info,
623        };
624        let mut exec_ctx = abi::ExecutionContext::new(
625            &params,
626            &code_info,
627            &instance_info,
628            <C::Runtime as Runtime>::Core::remaining_tx_gas(),
629            caller,
630            CurrentState::with_env(|env| env.is_read_only()),
631            CurrentState::with_env(|env| env.tx_call_format()),
632            ctx,
633        );
634        let result = wasm::call::<Cfg, C>(&mut exec_ctx, &contract, &body);
635
636        let result = results::process_execution_result(ctx, result)?;
637        let data = results::process_execution_success::<Cfg, C>(ctx, &params, &contract, result)?;
638        Ok(types::CallResult(data))
639    }
640
641    #[handler(call = "contracts.ChangeUpgradePolicy")]
642    pub fn tx_change_upgrade_policy<C: Context>(
643        ctx: &C,
644        body: types::ChangeUpgradePolicy,
645    ) -> Result<(), Error> {
646        let params = Self::params();
647        let caller = CurrentState::with_env(|env| env.tx_caller_address());
648
649        <C::Runtime as Runtime>::Core::use_tx_gas(params.gas_costs.tx_change_upgrade_policy)?;
650
651        if CurrentState::with_env(|env| env.is_check_only()) {
652            return Ok(());
653        }
654
655        // Load instance information.
656        let mut instance_info = Self::load_instance_info(body.id)?;
657        instance_info.upgrades_policy.enforce(&caller)?;
658
659        // Change upgrade policy.
660        instance_info.upgrades_policy = body.upgrades_policy;
661        Self::store_instance_info(instance_info.clone())?;
662
663        Ok(())
664    }
665
666    #[handler(call = "contracts.Upgrade")]
667    pub fn tx_upgrade<C: Context>(ctx: &C, body: types::Upgrade) -> Result<(), Error> {
668        let params = Self::params();
669        let caller = CurrentState::with_env(|env| env.tx_caller_address());
670
671        <C::Runtime as Runtime>::Core::use_tx_gas(params.gas_costs.tx_upgrade)?;
672
673        if !ctx.should_execute_contracts() {
674            // Only fast checks are allowed.
675            return Ok(());
676        }
677
678        // Load instance information and code.
679        let mut instance_info = Self::load_instance_info(body.id)?;
680        instance_info.upgrades_policy.enforce(&caller)?;
681        if instance_info.code_id == body.code_id {
682            return Err(Error::CodeAlreadyUpgraded(body.code_id.as_u64()));
683        }
684        let code_info = Self::load_code_info(instance_info.code_id)?;
685        let code = Self::load_code(&code_info)?;
686
687        // Transfer any attached tokens.
688        for tokens in &body.tokens {
689            <C::Runtime as Runtime>::Accounts::transfer(caller, instance_info.address(), tokens)
690                .map_err(|_| Error::InsufficientCallerBalance)?
691        }
692        // Run pre-upgrade function on the previous contract.
693        let contract = wasm::Contract {
694            code_info: &code_info,
695            code: &code,
696            instance_info: &instance_info,
697        };
698        let mut exec_ctx = abi::ExecutionContext::new(
699            &params,
700            &code_info,
701            &instance_info,
702            <C::Runtime as Runtime>::Core::remaining_tx_gas(),
703            caller,
704            CurrentState::with_env(|env| env.is_read_only()),
705            CurrentState::with_env(|env| env.tx_call_format()),
706            ctx,
707        );
708        // Pre-upgrade invocation must succeed for the upgrade to proceed.
709        let result = wasm::pre_upgrade::<Cfg, C>(&mut exec_ctx, &contract, &body);
710
711        results::process_execution_result(ctx, result)?;
712
713        // Update the contract code.
714        instance_info.code_id = body.code_id;
715        let code_info = Self::load_code_info(instance_info.code_id)?;
716        let code = Self::load_code(&code_info)?;
717        Self::store_instance_info(instance_info.clone())?;
718
719        let contract = wasm::Contract {
720            code_info: &code_info,
721            code: &code,
722            instance_info: &instance_info,
723        };
724        let mut exec_ctx = abi::ExecutionContext::new(
725            &params,
726            &code_info,
727            &instance_info,
728            <C::Runtime as Runtime>::Core::remaining_tx_gas(),
729            caller,
730            CurrentState::with_env(|env| env.is_read_only()),
731            CurrentState::with_env(|env| env.tx_call_format()),
732            ctx,
733        );
734
735        // Run post-upgrade function on the new contract.
736        let result = wasm::post_upgrade::<Cfg, C>(&mut exec_ctx, &contract, &body);
737        results::process_execution_result(ctx, result)?;
738        Ok(())
739    }
740
741    #[handler(query = "contracts.Code")]
742    pub fn query_code<C: Context>(_ctx: &C, args: types::CodeQuery) -> Result<types::Code, Error> {
743        Self::load_code_info(args.id)
744    }
745
746    #[handler(query = "contracts.CodeStorage")]
747    pub fn query_code_storage<C: Context>(
748        _ctx: &C,
749        args: types::CodeStorageQuery,
750    ) -> Result<types::CodeStorageQueryResult, Error> {
751        let code_info = Self::load_code_info(args.id)?;
752        let code = Self::load_code(&code_info)?;
753
754        Ok(types::CodeStorageQueryResult { code })
755    }
756
757    #[handler(query = "contracts.Instance")]
758    pub fn query_instance<C: Context>(
759        _ctx: &C,
760        args: types::InstanceQuery,
761    ) -> Result<types::Instance, Error> {
762        Self::load_instance_info(args.id)
763    }
764
765    #[handler(query = "contracts.InstanceStorage")]
766    pub fn query_instance_storage<C: Context>(
767        ctx: &C,
768        args: types::InstanceStorageQuery,
769    ) -> Result<types::InstanceStorageQueryResult, Error> {
770        let instance_info = Self::load_instance_info(args.id)?;
771        // NOTE: We can only access the public store here.
772        let value = store::with_instance_store(ctx, &instance_info, StoreKind::Public, |store| {
773            store.get(&args.key)
774        })?;
775
776        Ok(types::InstanceStorageQueryResult { value })
777    }
778
779    #[handler(query = "contracts.InstanceRawStorage", expensive)]
780    pub fn query_instance_raw_storage<C: Context>(
781        ctx: &C,
782        args: types::InstanceRawStorageQuery,
783    ) -> Result<types::InstanceRawStorageQueryResult, Error> {
784        let cfg: LocalConfig = ctx.local_config(MODULE_NAME).unwrap_or_default();
785        let limit: usize = args
786            .limit
787            .unwrap_or(u64::MAX)
788            .min(cfg.max_instance_raw_storage_query_items)
789            .try_into()
790            .map_err(|_| Error::InvalidArgument)?;
791        let offset: usize = args
792            .offset
793            .unwrap_or(0)
794            .try_into()
795            .map_err(|_| Error::InvalidArgument)?;
796
797        let instance_info = Self::load_instance_info(args.id)?;
798        // Convert contracts API StoreKind to internal storage StoreKind.
799        let sk: StoreKind = (args.store_kind as u32)
800            .try_into()
801            .map_err(|_| Error::InvalidArgument)?;
802
803        let items: Vec<(Vec<u8>, Vec<u8>)> = with_instance_raw_store(&instance_info, sk, |store| {
804            store
805                .iter()
806                // Shave off first 32 bytes of the key to get the contract instance-level key name.
807                .filter(|(k, _)| k.len() >= 32)
808                .map(|(k, v)| (k[32..].to_vec(), v.to_vec()))
809                .skip(offset)
810                .take(limit)
811                .collect()
812        });
813
814        Ok(types::InstanceRawStorageQueryResult { items })
815    }
816
817    #[handler(query = "contracts.PublicKey")]
818    pub fn query_public_key<C: Context>(
819        _ctx: &C,
820        _args: types::PublicKeyQuery,
821    ) -> Result<types::PublicKeyQueryResult, Error> {
822        Err(Error::Unsupported)
823    }
824
825    #[handler(query = "contracts.Custom", expensive)]
826    pub fn query_custom<C: Context>(
827        ctx: &C,
828        args: types::CustomQuery,
829    ) -> Result<types::CustomQueryResult, Error> {
830        let params = Self::params();
831
832        // Load instance information and code.
833        let instance_info = Self::load_instance_info(args.id)?;
834        let code_info = Self::load_code_info(instance_info.code_id)?;
835        let code = Self::load_code(&code_info)?;
836
837        // Load local configuration.
838        let cfg: LocalConfig = ctx.local_config(MODULE_NAME).unwrap_or_default();
839
840        // Run query function.
841        let contract = wasm::Contract {
842            code_info: &code_info,
843            code: &code,
844            instance_info: &instance_info,
845        };
846        let mut exec_ctx = abi::ExecutionContext::new(
847            &params,
848            &code_info,
849            &instance_info,
850            cfg.query_custom_max_gas,
851            Default::default(), // No caller for queries.
852            true,
853            CallFormat::Plain,
854            ctx,
855        );
856        let result = wasm::query::<Cfg, C>(&mut exec_ctx, &contract, &args).inner?; // No need to handle gas.
857
858        Ok(types::CustomQueryResult(result.data))
859    }
860}
861
862impl<Cfg: Config> module::TransactionHandler for Module<Cfg> {}
863impl<Cfg: Config> module::BlockHandler for Module<Cfg> {}
864impl<Cfg: Config> module::InvariantHandler for Module<Cfg> {}