concordium_std/
lib.rs

1//! This library provides the core API that can be used to write smart contracts
2//! for the Concordium blockchain. It aims to provide safe wrappers around the
3//! core primitives exposed by the chain and accessible to smart contracts.
4//!
5//! The library is meant to be used as a standard library for developing smart
6//! contracts. For this reason it re-exports a number of definitions from other
7//! libraries.
8//!
9//! # Versions
10//!
11//! The concordium blockchain at present supports two variants of smart
12//! contracts. The original V0 contracts that use message-passing for
13//! communication and have limited state, and V1 contracts which use synchronous
14//! calls, and have extended state. Versions 1 and 2 of `concordium-std`
15//! **support only V0 contracts**. Version 3 and later of `concordium-std`
16//! **supports only V1 contracts**.
17//!
18//! Also note that `concordium-std` version 4 only works with `cargo-concordium`
19//! version 2.1+.
20//!
21//! Version 8.1 deprecates the module [`test_infrastructure`] in favor of the
22//! library [concordium_smart_contract_testing], which should be used instead.
23//! For more details including how to migrate your contract, see the
24//! [Deprecating the
25//! `test_infrastructure`](#deprecating-the-test_infrastructure) section.
26//!
27//! # Panic handler
28//!
29//! When compiled without the `std` feature this crate sets the panic handler
30//! so that it terminates the process immediately, without any unwinding or
31//! prints.
32//! Concretely, when compiled to the `wasm32` target panic boils down to the
33//! `unreachable` instruction, which triggers a runtime failure, aborting
34//! execution of the program.
35//!
36//! # Features
37//!
38//! This library has the following features:
39//! [`std`](#std-build-with-the-rust-standard-library),
40//! [`build-schema`](#build-schema-build-for-generating-a-module-schema),
41//! [`wasm-test`](#wasm-test-build-for-testing-in-wasm),
42//! [`crypto-primitives`][crypto-feature], and
43//! [`bump_alloc`](#use-a-custom-allocator)
44//! [`debug`](#emit-debug-information)
45//!
46//! [crypto-feature]:
47//! #crypto-primitives-for-testing-crypto-with-actual-implementations
48//!
49//! ## `std`: Build with the Rust standard library
50//!
51//! By default this library will be linked with the
52//! [std](https://doc.rust-lang.org/std/) crate, the rust standard library,
53//! however to minimize code size this library supports toggling compilation
54//! with the `#![no_std]` attribute via the feature `std` which is enabled by
55//! default. Compilation without the `std` feature requires a nightly version of
56//! rust.
57//!
58//! To use this library without the `std` feature you have to disable it, which
59//! can be done, for example, as follows.
60//! ```toml
61//! [dependencies.concordium-std]
62//! default-features = false
63//! ```
64//! In your project's `Cargo.toml` file.
65//!
66//! ## `build-schema`: Build for generating a module schema
67//!
68//! **WARNING** Building with this feature enabled is meant for tooling, and the
69//! result is not intended to be deployed on chain.
70//!
71//! This library provides a way to automate the building of smart contract
72//! module schema, by allowing the contract to be built exporting getter
73//! functions for the `concordium_contracts_common::schema::Type` of Types for
74//! contract state and parameters.
75//! This special build is only intended to be used for generating the schema
76//! and is not meant to be deployed, since the build exports functions that do
77//! not conform to the expected API of smart contracts.
78//! The build is enabled by setting the feature `build-schema`.
79//!
80//! **Note** This feature is used by `cargo-concordium`, when building with
81//! schema and for most cases this feature should not be set manually.
82//!
83//! ## `wasm-test`: Build for testing in Wasm
84//!
85//! **WARNING** Building with this feature enabled is meant for tooling, and the
86//! result is not intended to be deployed on chain.
87//!
88//! The macros [`#[concordium_test]`](attr.concordium_test.html) and
89//! [`#[concordium_cfg_test]`](attr.concordium_cfg_test.html) are reduced to
90//! `#[test]` and `#[cfg(test)]` unless the `wasm-test` feature is enabled.
91//!
92//! With the `wasm-test` feature enabled, the
93//! [`#[concordium_test]`](attr.concordium_test.html) macro exports the test as
94//! an `extern` function, allowing tools such as `cargo-concordium` to call the
95//! test functions directly, when compiled to Wasm.
96//! Without the feature it falls back to `#[test]`.
97//!
98//! With the 'wasm-test' feature enabled, the
99//! [`#[concordium_cfg_test]`](attr.concordium_cfg_test.html) macro allows the
100//! annotated code to be included in the build. Without the feature, it falls
101//! back to `#[cfg(test)]`.
102//!
103//! **Note** This feature is used by `cargo-concordium`, when building for
104//! testing and for most cases this feature should not be set manually.
105//!
106//! ## `crypto-primitives`: For testing crypto with actual implementations
107//!
108//! This features is only relevant when using the **deprecated**
109//! [test_infrastructure].
110//!
111//! Build with this feature if you want to run smart contract tests with actual
112//! (i.e., not mock) implementations of the cryptographic primitives from
113//! [`HasCryptoPrimitives`].
114//!
115//! **WARNING**: It is not possible to build this crate on macOS with the
116//! `crypto-primitives` feature when targeting `wasm32-unknown-unknown`.
117//! The issue arises when compiling the [`secp256k1`](https://docs.rs/secp256k1/latest/secp256k1/) crate.
118//!
119//! ## Use a custom allocator
120//!
121//! Some operations in `concordium-std` need to dynamically allocate memory.
122//! Rust programs compiled with default compiler settings have access to a
123//! [standard allocator](https://doc.rust-lang.org/std/alloc/struct.System.html)
124//! implemented in the Rust standard library. When using the
125//! `no-std` feature there is no default allocator provided by the Rust
126//! toolchain, and so one must be set explicitly.
127//!
128//! In the past `concordium-std` hard-coded the use of [wee_alloc](https://docs.rs/wee_alloc/)
129//! however since version `5.2.0` this is no longer the case.
130//! Instead no allocator is set by default, however there is a `bump_alloc`
131//! feature (disabled by default) that can be enabled which sets the allocator
132//! to `bump_alloc`, which ships with `concordium-std`. This can be used both
133//! with and without the `std` feature.
134//!
135//! The main reason for using `bump_alloc` instead of the default allocator,
136//! even in `std` builds, is that `bump_alloc` has a smaller code footprint,
137//! i.e, the resulting smart contracts are going to be smaller by about 6-10kB,
138//! which means they are cheaper to deploy and run. `bump_alloc` is designed to
139//! be simple and fast, but it does not use the memory very efficiently. For
140//! short-lived programs, such as smart contracts, this is usually the right
141//! tradeoff. Especially for contracts such as those dealing with tokens.
142//! For very complex contracts it may be beneficial to run benchmarks to see
143//! whether `bump_alloc` is the best option. See the Rust [allocator](https://doc.rust-lang.org/std/alloc/index.html#the-global_allocator-attribute)
144//! documentation for more context and details on using custom allocators.
145//!
146//! # Emit debug information
147//!
148//! During testing and debugging it is often useful to emit debug information to
149//! narrow down the source of the problem. `concordium-std` supports this using
150//! the [`concordium_dbg`] macro which will emit its arguments using a special
151//! host function `debug_print` which is only available when the `debug` feature
152//! is enabled. The output of this function is used by `cargo concordium run`
153//! and `cargo concordium test` to display any output that was emitted.
154//!
155//! The `debug` feature should typically not be enabled manually. It is used
156//! implicitly by `cargo concordium` when debug output is requested. It is also
157//! **crucial** that the `debug` feature is **not** enabled when building the
158//! contract for deployment. If it is the contract is most likely to be rejected
159//! when it is being deployed to the chain. The `concordium_dbg!` macro will
160//! ignore its arguments when the `debug` feature is not enabled.
161//!
162//! # Essential types
163//!
164//! This crate has a number of essential types that are used when writing smart
165//! contracts. The structure of these are, at present, a bit odd without the
166//! historic context, which is explained below.
167//!
168//! Prior to version 8.1, a number of traits and generics were used when writing
169//! smart contracts, e.g. [`HasHost`], to support the usage of
170//! [`crate::test_infrastructure`] for testing, where two primary
171//! implementations of each trait existed. The first one is supported by
172//! **host** functions, and this is the implementation that is used when
173//! contracts are executed by notes. The second set of implementations supports
174//! testing contracts with [`crate::test_infrastructure`], but since the
175//! deprecation of this module, the preferred way of writing contracts is to use
176//! the concrete types.
177//!
178//! The essential concrete types are:
179//! - [`StateApi`] for operations possible on the contract state
180//! - [`Host`] for invoking operations on the host and accessing the state
181//! - [`InitContext`] for all the context data available to the init functions
182//! - [`ReceiveContext`] for accessing all the context data available to the
183//!   receive functions
184//! - [`ExternParameter`] for accessing the contract parameter
185//! - [`Logger`] for logging data during smart contract execution
186//! - [`Policy`] for accessing the policy of the sender, either of the init or
187//!   receive method
188//! - [`CryptoPrimitives`] for using cryptographic primitives such as hashing
189//!   and signature verification.
190//!
191//! Most of these are type aliases for similarly named structs prefixed with
192//! `Extern`. The extern prefix made sense when two different implementations of
193//! the traits were in play. Since that is no longer the case, we decided to
194//! simplify the names with aliases.
195//!
196//! # Signalling errors
197//!
198//! On the Wasm level contracts can signal errors by returning a negative i32
199//! value as a result of either initialization or invocation of the receive
200//! method. If the error is a logic error and the contract executes successfully
201//! then it can also produce a return value, which may provide additional detail
202//! of the error to the caller. To make error handling more pleasant we provide
203//! the [Reject](./struct.Reject.html) structure. The result type of a contract
204//! init or a receive method is assumed to be of the form `Result<_, E>` where
205//! `Reject: From<E>`.
206//!
207//! Producing return values is in case of errors is not yet supported by this
208//! library, although smart contract writers can do this manually using the
209//! [Write] implementation of the [ExternReturnValue] type.
210//!
211//! With respect to error **codes**, the intention is that smart contract
212//! writers will write their own custom, precise, error types and either
213//! manually implement `Reject: From<E>` for their type `E`, or use the [Reject
214//! macro](./derive.Reject.html) which supports the common use cases.
215//!
216//! In addition to the custom errors that signal contract-specific error
217//! conditions this library provides some common error cases that most contracts
218//! will have to handle and their conversions to [Reject](./struct.Reject.html).
219//! These are
220//!
221//! | Variant | Error code |
222//! |---------|------------|
223//! | [()][1] | `-2147483647` |
224//! | [ParseError] | `-2147483646` |
225//! | [LogError::Full] | `-2147483645` |
226//! | [LogError::Malformed] | `-2147483644`
227//! | [NewContractNameError::MissingInitPrefix] | `-2147483643` |
228//! | [NewContractNameError::TooLong] | `-2147483642` |
229//! | [NewContractNameError::ContainsDot] | `-2147483639` |
230//! | [NewContractNameError::InvalidCharacters] | `-2147483638` |
231//! | [NewReceiveNameError::MissingDotSeparator] | `-2147483641` |
232//! | [NewReceiveNameError::TooLong] | `-2147483640` |
233//! | [NewReceiveNameError::InvalidCharacters] | `-2147483637` |
234//! | [NotPayableError] | `-2147483636` |
235//! | [TransferError::AmountTooLarge] | `-2147483635` |
236//! | [TransferError::MissingAccount] | `-2147483634` |
237//! | [CallContractError::AmountTooLarge] | `-2147483633` |
238//! | [CallContractError::MissingAccount] | `-2147483632` |
239//! | [CallContractError::MissingContract] | `-2147483631` |
240//! | [CallContractError::MissingEntrypoint] | `-2147483630` |
241//! | [CallContractError::MessageFailed] | `-2147483629` |
242//! | [CallContractError::LogicReject] | `-2147483628` |
243//! | [CallContractError::Trap] | `-2147483627` |
244//! | [UpgradeError::MissingModule] | `-2147483626` |
245//! | [UpgradeError::MissingContract] | `-2147483625` |
246//! | [UpgradeError::UnsupportedModuleVersion] | `-2147483624` |
247//! | [QueryAccountBalanceError] | `-2147483623` |
248//! | [QueryContractBalanceError] | `-2147483622` |
249//!
250//! Other error codes may be added in the future and custom error codes should
251//! not use the range `i32::MIN` to `i32::MIN + 100`.
252//!
253//! # Collections
254//!
255//! Several collections are available for use in a smart contract and choosing
256//! the right one can result in significant cost savings.
257//!
258//! First off, Rust's own standard library provides [several efficient data structures](https://doc.rust-lang.org/std/collections/)
259//! which can be used in a smart contract.
260//!
261//! However, these can become costly for collections holding a large number of
262//! elements, which needs to be persisted in the smart contract state across
263//! contract updates.
264//! The reason being these data structures are designed to be kept in-memory and
265//! persisting them means reading and writing the entire collection to a single
266//! entry in the smart contract key-value store on every contract update.
267//! This is wasteful when only part of the collection is relevant on each
268//! update.
269//!
270//! In the above mentioned scenarios, it is instead recommended to use one of
271//! the smart contract tailored collections, as these partisions the collection
272//! into multiple key-value stores, resulting in cheaper read and writes to the
273//! state.
274//!
275//! The collections can be grouped as:
276//! - Maps: [`StateMap`], [`StateBTreeMap`]
277//! - Sets: [`StateSet`], [`StateBTreeSet`]
278//!
279//! ## When should you use which collection?
280//!
281//! This section presents a rough guideline for when to reach for each of the
282//! collections.
283//!
284//! ### Use `StateMap` when:
285//!
286//! - You want to track which keys you have seen.
287//! - Arbitrary values are associated with each of the keys.
288//!
289//! ### Use `StateBTreeMap` when:
290//!
291//! - You want to track which keys you have seen.
292//! - Arbitrary values are associated with each of the keys.
293//! - The keys have some _ordering_ which is relevant e.g. if you need the key
294//!   which is located right above/below another key using
295//!   [`higher`](StateBTreeMap::higher)/[`lower`](StateBTreeMap::lower).
296//!
297//! ### Use `StateSet` when:
298//!
299//! - You want to track which keys you have seen.
300//! - There is no meaningful value to associate with your keys.
301//!
302//! ### Use `StateBTreeSet` when:
303//!
304//! - You want to track which keys you have seen.
305//! - There is no meaningful value to associate with your keys.
306//! - The keys have some _ordering_ which is relevant e.g. if you need the key
307//!   which is located right above/below another key using
308//!   [`higher`](StateBTreeMap::higher)/[`lower`](StateBTreeMap::lower).
309//!
310//! # Deprecating the `test_infrastructure`
311//!
312//! Version 8.1 deprecates the [test_infrastructure] in favor of the library
313//! [concordium_smart_contract_testing]. A number of traits are also
314//! deprecated at the same time since they only exist to support the
315//! [test_infrastructure] and are not needed in the new testing library.
316//! The primary of these traits are [`HasHost`], [`HasStateApi`],
317//! [`HasInitContext`], and [`HasReceiveContext`].
318//!
319//! ## Migration guide
320//! To migrate your contract and its tests to the new testing library, you need
321//! to do the following two steps:
322//!
323//! 1. Replace the usage of deprecated traits with their concrete alternatives
324//! and remove generics.
325//!
326//!    For init methods:
327//!    ```no_run
328//!    # use concordium_std::*;
329//!    #
330//!    # type State = ();
331//!    #
332//!    /// Before
333//!    #[init(contract = "contract_before")]
334//!    fn init_before<S: HasStateApi>(
335//!        ctx: &impl HasInitContext,
336//!        state_builder: &mut StateBuilder<S>,
337//!    ) -> InitResult<State> { todo!() }
338//!
339//!    /// After
340//!    #[init(contract = "contract_after")]
341//!    fn init_after(                        // `<S: HasStateApi>` removed
342//!        ctx: &InitContext,                // `impl` and `Has` removed
343//!        state_builder: &mut StateBuilder, // `<S>` removed
344//!    ) -> InitResult<State> { todo!() }
345//!    ```
346//!    For receive methods:
347//!    ```no_run
348//!    # use concordium_std::*;
349//!    #
350//!    # type State = ();
351//!    # type MyReturnValue = ();
352//!    #
353//!    # #[init(contract = "my_contract")]
354//!    # fn contract_init(                    // `<S: HasStateApi>` removed
355//!    #    ctx: &InitContext,                // `impl` and `Has` removed
356//!    #    state_builder: &mut StateBuilder, // `<S>` removed
357//!    # ) -> InitResult<State> { todo!() }
358//!    /// Before
359//!    #[receive(contract = "my_contract", name = "my_receive")]
360//!    fn receive_before<S: HasStateApi>(
361//!        ctx: &impl HasReceiveContext,
362//!        host: &impl HasHost<State, StateApiType = S>,
363//!    ) -> ReceiveResult<MyReturnValue> { todo!() }
364//!
365//!    /// After
366//!    #[receive(contract = "my_contract", name = "my_receive")]
367//!    fn receive_after(           // `<S: HasStateApi>` removed
368//!        ctx: &ReceiveContext,   // `impl` and `Has` removed
369//!        host: &Host<State>,     // `impl Has` and `, StateApiType = S removed
370//!    ) -> ReceiveResult<MyReturnValue> { todo!() }
371//!    ```
372//!
373//!    If you use logging, crypto-primitives, or similar, you must also
374//! replace those uses of traits with concrete types. E.g. replacing `&mut impl
375//! HasLogger` with `&mut Logger`.
376//!
377//! 2. Migrate your tests to use the new testing library.
378//!
379//!    For an introduction to the library, see our [guide](https://developer.concordium.software/en/mainnet/smart-contracts/guides/integration-test-contract.html).
380//!
381//!    If you follow our [recommended structure](https://developer.concordium.software/en/mainnet/smart-contracts/best-practices/development.html#recommended-structure) in your contract,
382//!    then you have a mix of unit and integrations tests:
383//!    - Unit tests that call methods directly on your state struct (without any
384//!      init/receive calls)
385//!    - Integration tests that call the init and receive methods
386//!
387//! If you do not want to migrate your contract and tests yet, then you can add
388//! the `#[allow(deprecated)]` attribute to your test modules to avoid the
389//! deprecation warnings.
390//!
391//! [1]: https://doc.rust-lang.org/std/primitive.unit.html
392//! [test_infrastructure]: ./test_infrastructure/index.html
393//! [concordium_smart_contract_testing]: https://docs.rs/concordium-smart-contract-testing
394
395#![cfg_attr(not(feature = "std"), no_std, feature(core_intrinsics))]
396
397#[cfg(not(feature = "std"))]
398pub extern crate alloc;
399
400/// Terminate execution immediately without panicking.
401/// When the `std` feature is enabled this is just [std::process::abort](https://doc.rust-lang.org/std/process/fn.abort.html).
402/// When `std` is not present and the target architecture is `wasm32` this will
403/// simply emit the [unreachable](https://doc.rust-lang.org/core/arch/wasm32/fn.unreachable.html) instruction.
404#[cfg(feature = "std")]
405pub use std::process::abort as trap;
406#[cfg(all(not(feature = "std"), target_arch = "wasm32"))]
407#[inline(always)]
408pub fn trap() -> ! { core::arch::wasm32::unreachable() }
409#[cfg(all(not(feature = "std"), not(target_arch = "wasm32")))]
410#[inline(always)]
411pub fn trap() -> ! { core::intrinsics::abort() }
412
413#[cfg(not(feature = "std"))]
414#[panic_handler]
415fn abort_panic(_info: &core::panic::PanicInfo) -> ! {
416    #[cfg(target_arch = "wasm32")]
417    core::arch::wasm32::unreachable();
418    #[cfg(not(target_arch = "wasm32"))]
419    loop {}
420}
421
422// Provide some re-exports to make it easier to use the library.
423// This should be expanded in the future.
424/// Re-export.
425#[cfg(not(feature = "std"))]
426pub use alloc::{
427    borrow::ToOwned, boxed, boxed::Box, format, rc, string, string::String, string::ToString, vec,
428    vec::Vec,
429};
430/// Re-export.
431#[cfg(not(feature = "std"))]
432pub use core::{cell, cmp, convert, fmt, hash, hint, iter, marker, mem, num, ops, result::*};
433#[cfg(feature = "std")]
434pub(crate) use std::vec;
435
436/// Re-export.
437#[cfg(feature = "std")]
438pub use std::{
439    boxed, boxed::Box, cell, cmp, convert, fmt, hash, hint, iter, marker, mem, num, ops, rc,
440    string::String, vec::Vec,
441};
442
443#[cfg(all(feature = "bump_alloc", target_arch = "wasm32"))]
444pub mod bump_alloc;
445
446#[cfg(all(feature = "bump_alloc", target_arch = "wasm32"))]
447#[cfg_attr(feature = "bump_alloc", global_allocator)]
448static ALLOC: crate::bump_alloc::BumpAllocator = unsafe { crate::bump_alloc::BumpAllocator::new() };
449
450/// Re-export.
451pub mod collections {
452    #[cfg(not(feature = "std"))]
453    use alloc::collections;
454    #[cfg(feature = "std")]
455    use std::collections;
456
457    pub use collections::*;
458    pub use concordium_contracts_common::{HashMap, HashSet};
459}
460
461pub mod constants;
462mod impls;
463pub mod prims;
464mod state_btree;
465mod traits;
466mod types;
467pub use concordium_contracts_common::*;
468pub use impls::*;
469pub use state_btree::*;
470pub use traits::*;
471pub use types::*;
472
473#[deprecated(
474    since = "8.1.0",
475    note = "Deprecated in favor of [concordium-smart-contract-testing](https://docs.rs/concordium-smart-contract-testing)."
476)]
477pub mod test_infrastructure;
478
479#[cfg(all(feature = "debug", not(feature = "std")))]
480pub use alloc::format;
481#[cfg(all(feature = "debug", feature = "std"))]
482pub use std::format;
483
484#[macro_export]
485#[cfg(feature = "debug")]
486/// When the `debug` feature of `concordium-std` is enabled this will use the
487/// `debug_print` host function to emit the provided information. The syntax is
488/// the same as that of `println!` macro.
489///
490/// If the `debug` feature is not enabled the macro generates an empty
491/// expression.
492macro_rules! concordium_dbg {
493    () => {
494        {
495            $crate::debug_print("", file!(), line!(), column!());
496        }
497    };
498    ($($arg:tt)*) => {
499        {
500            let msg = $crate::format!($($arg)*);
501            $crate::debug_print(&msg, file!(), line!(), column!());
502        }
503    };
504}
505
506#[macro_export]
507#[cfg(not(feature = "debug"))]
508/// When the `debug` feature of `concordium-std` is enabled this will use the
509/// `debug_print` host function to emit the provided information. The syntax is
510/// the same as that of `println!` macro.
511///
512/// If the `debug` feature is not enabled the macro generates an empty
513/// expression.
514macro_rules! concordium_dbg {
515    () => {{}};
516    ($($arg:tt)*) => {{}};
517}
518
519/// Emit a message in debug mode.
520/// Used internally, not meant to be called directly by contract writers,
521/// and a contract with this debug print cannot be deployed to the chain.
522#[doc(hidden)]
523#[cfg(feature = "debug")]
524pub fn debug_print(message: &str, filename: &str, line: u32, column: u32) {
525    let msg_bytes = message.as_bytes();
526    let filename_bytes = filename.as_bytes();
527    unsafe {
528        crate::prims::debug_print(
529            msg_bytes.as_ptr(),
530            msg_bytes.len() as u32,
531            filename_bytes.as_ptr(),
532            filename_bytes.len() as u32,
533            line,
534            column,
535        )
536    };
537}