Crate concordium_std
source ·Expand description
This library provides the core API that can be used to write smart contracts for the Concordium blockchain. It aims to provide safe wrappers around the core primitives exposed by the chain and accessible to smart contracts.
The library is meant to be used as a standard library for developing smart contracts. For this reason it re-exports a number of definitions from other libraries.
Versions
The concordium blockchain at present supports two variants of smart
contracts. The original V0 contracts that use message-passing for
communication and have limited state, and V1 contracts which use synchronous
calls, and have extended state. Versions 1 and 2 of concordium-std
support only V0 contracts. Version 3 and later of concordium-std
supports only V1 contracts.
Also note that concordium-std
version 4 only works with cargo-concordium
version 2.1+.
Panic handler
When compiled without the std
feature this crate sets the panic handler
so that it terminates the process immediately, without any unwinding or
prints.
Concretely, when compiled to the wasm32
target panic boils down to the
unreachable
instruction, which triggers a runtime failure, aborting
execution of the program.
Features
This library has the following features:
std
,
build-schema
,
wasm-test
,
crypto-primitives
, and
wee_alloc
std
: Build with the Rust standard library
By default this library will be linked with the
std crate, the rust standard library,
however to minimize code size this library supports toggling compilation
with the #![no_std]
attribute via the feature std
which is enabled by
default. Compilation without the std
feature requires a nightly version of
rust.
To use this library without the std
feature you have to disable it, which
can be done, for example, as follows.
[dependencies.concordium-std]
default-features = false
In your project’s Cargo.toml
file.
build-schema
: Build for generating a module schema
WARNING Building with this feature enabled is meant for tooling, and the result is not intended to be deployed on chain.
This library provides a way to automate the building of smart contract
module schema, by allowing the contract to be built exporting getter
functions for the concordium_contracts_common::schema::Type
of Types for
contract state and parameters.
This special build is only intended to be used for generating the schema
and is not meant to be deployed, since the build exports functions that do
not conform to the expected API of smart contracts.
The build is enabled by setting the feature build-schema
.
Note This feature is used by cargo-concordium
, when building with
schema and for most cases this feature should not be set manually.
wasm-test
: Build for testing in Wasm
WARNING Building with this feature enabled is meant for tooling, and the result is not intended to be deployed on chain.
The macros #[concordium_test]
and
#[concordium_cfg_test]
are reduced to
#[test]
and #[cfg(test)]
unless the wasm-test
feature is enabled.
With the wasm-test
feature enabled, the
#[concordium_test]
macro exports the test as
an extern
function, allowing tools such as cargo-concordium
to call the
test functions directly, when compiled to Wasm.
Without the feature it falls back to #[test]
.
With the ‘wasm-test’ feature enabled, the
#[concordium_cfg_test]
macro allows the
annotated code to be included in the build. Without the feature, it falls
back to #[cfg(test)]
.
Note This feature is used by cargo-concordium
, when building for
testing and for most cases this feature should not be set manually.
crypto-primitives
: For testing crypto with actual implementations
Build with this feature if you want to run smart contract tests with actual
(i.e., not mock) implementations of the cryptographic primitives from
HasCryptoPrimitives
.
WARNING: It is not possible to build this crate on macOS with the
crypto-primitives
feature when targeting wasm32-unknown-unknown
.
The issue arises when compiling the secp256k1
crate.
Use a custom allocator
Some operations in concordium-std
need to dynamically allocate memory.
Rust programs compiled with default compiler settings have access to a
standard allocator
implemented in the Rust standard library. When using the
no-std
feature there is no default allocator provided by the Rust
toolchain, and so one must be set explicitly.
In the past concordium-std
hard-coded the use of wee_alloc
however since version 5.2.0
this is no longer the case.
Instead no allocator is set by default, however there is a wee_alloc
feature (disabled by default) that can be enabled which sets the allocator
to wee_alloc
. This can be used both with and without the std
feature.
The main reason for using wee_alloc
instead of the default allocator, even
in std
builds, is that wee_alloc
has a smaller code footprint, i.e, the
resulting smart contracts are going to be smaller by about 6-10kB, which
means they are cheaper to deploy and run. The downside is that this
allocator is designed to be used in contexts where there are a few
large allocations up-front, and the memory is afterward used by the program
without many further allocations. Frequent small allocations will have bad
performance, and should be avoided. Do note that this allocator is
at present unmaintained. There are other allocators available, for example dlmalloc.
We only provide wee_alloc
via a feature for backwards compatibility.
Configuration of other allocators should follow their respective
documentation, however note that there can only be one allocator set.
See Rust allocator documentation for more context and details.
Traits
To support testing of smart contracts most of the functionality is accessible via traits. This library generally provides two implementations of most traits. The first one is supported by host functions, and this is the implementation that is used when contracts are executed by nodes. The second set of implementations supports testing of contracts and it is defined in the test_infrastructure module.
- HasParameter for accessing the contract parameter
- HasCommonData for accessing the data that is common to both init and receive methods
- HasInitContext for all the context data available to the init functions (note that this includes all the common data)
- HasReceiveContext for accessing all the context data available to the receive functions (note that this includes all the common data)
- HasLogger for logging data during smart contract execution
- HasPolicy for accessing the policy of the sender, either of the init or receive method
- HasStateApi for operations possible on the contract state
- HasHost for invoking operations on the host and accessing the state
- HasCryptoPrimitives for using cryptographic primitives such as hashing and signature verification.
Signalling errors
On the Wasm level contracts can signal errors by returning a negative i32
value as a result of either initialization or invocation of the receive
method. If the error is a logic error and the contract executes successfully
then it can also produce a return value, which may provide additional detail
of the error to the caller. To make error handling more pleasant we provide
the Reject structure. The result type of a contract
init or a receive method is assumed to be of the form Result<_, E>
where
Reject: From<E>
.
Producing return values is in case of errors is not yet supported by this library, although smart contract writers can do this manually using the Write implementation of the ExternReturnValue type.
With respect to error codes, the intention is that smart contract
writers will write their own custom, precise, error types and either
manually implement Reject: From<E>
for their type E
, or use the Reject
macro which supports the common use cases.
In addition to the custom errors that signal contract-specific error conditions this library provides some common error cases that most contracts will have to handle and their conversions to Reject. These are
Other error codes may be added in the future and custom error codes should
not use the range i32::MIN
to i32::MIN + 100
.
Modules
Box<T>
type for heap allocation.String
s.HasInitContext
, HasReceiveContext
, HasParameter
, HasStateApi
,
and HasHost
traits intended for testing.Macros
bail
macro can be used for cleaner error handling. If the function has
result type Result
invoking bail
will terminate execution early with an
error.
If an argument is supplied, this will be used as the error, otherwise it
requires the type E
in Result<_, E>
to implement the Default
trait.claim
macro is used for testing as a substitute for the assert macro.
It checks the condition and if false it reports back an error.
Used only in testing.assert_eq!
, otherwise
reports an error. Used only in testing.assert_ne!
,
otherwise reports an error.
Used only in testing.ensure
macro can be used for cleaner error handling. It is analogous
to assert
, but instead of panicking it uses bail
to terminate execution
of the function early.ensure
for ease of use in certain contexts.bail
otherwise.fail
macro is used for testing as a substitute for the panic macro.
It reports back error information to the host.
Used only in testing.Structs
T
.payable
.StateMap
. It can be obtained via the
StateMap::entry
method. This allows looking up or modifying the value at
a give key in-place.HasStateApi
type. It is part of the EntryRaw
enum.as_entrypoint_name
and the
methods on the EntrypointName
type.ReceiveName
type, the intention is to access those via the
as_receive_name
method.AttributeTag
and
AttributeValue
.StateMap
, StateSet
, and
StateBox
. It is parametrized by a parameter S
that is assumed to
implement HasStateApi
.StateMap
.StateMap
.StateRef
behaves akin the type &'a V
, except that it is not
copyable. It should be used as MutexGuard or
similar types which guard access to a resource.StateRefMut<_, V, _>
behaves like &mut V
, by analogy with other
standard library RAII guards like RefMut
.
The type implements DerefMut
which allows the
value to be mutated. Additionally, the Drop
implementation ensures
that the value is properly stored in the contract state maintained by the
node.StateMap
.HasStateApi
type.
It is part of the EntryRaw
enum.Vec<T>
, short for ‘vector’.Enums
HasStateApi
type,
which may either be vacant or occupied.AttributeValue
.std::io
, as well as to use 32-bit integers to specify positions. This
saves some computation and space, and is adequate for the kind of data sizes
that are possible in smart contracts.HasStateApi
.Constants
Traits
Deserial
trait provides a means of reading structures from
byte-sources (Read
).DeserialCtx
trait provides a means of reading structures from
byte-sources (Read
) using contextual information.
The contextual information is:DeserialCtxWithState
trait provides a means of reading structures from
byte-sources (Read
) using contextual information for types that also
need a reference to a HasStateApi
type. The trait is a combination
of the DeserialCtx
and DeserialWithState
traits, which each has
additional documentation.DeserialWithState
trait provides a means of reading structures from
byte-sources (Read
) for types that also need a reference to a
HasStateApi
type.expect_err
methods on Result,
but useful in a Wasm setting.expect_none
methods on Option,
but useful in a Wasm setting.expect
methods on types such as Option,
but useful in a Wasm setting.Deserial
that makes it easier to write
deserialization code. It has a blanked implementation for any read and
serialize pair. The key idea is that the type to deserialize is inferred
from the context, enabling one to write, for example,HasSize
trait provides a function for getting the current byte size.Read
trait provides a means of reading from byte streams.Seek
trait provides a cursor which can be moved within a stream of
bytes. This is essentially a copy of
std::io::Seek, but
avoiding its dependency on std::io::Error
, and the associated code size
increase. Additionally, the positions are expressed in terms of 32-bit
integers since this is adequate for the sizes of data in smart contracts.Serial
trait provides a means of writing structures into byte-sinks
(Write
).SerialCtx
trait provides a means of writing structures into byte-sinks
(Write
) using contextual information.
The contextual information is:Serialize
trait provides a means of writing structures into byte-sinks
(Write
) or reading structures from byte sources (Read
).Write
trait provides functionality for writing to byte streams.Functions
deserial_map_no_length
as it is skipping the
order checkingdeserial_set_no_length
as it is skipping the
order checking. The only check that is made to the set is that there are no
duplicates.to_bytes
.Serial
instance.std
feature is enabled this is just std::process::abort.
When std
is not present and the target architecture is wasm32
this will
simply emit the unreachable instruction.
Terminates the process in an abnormal fashion.Type Definitions
Result
that fixes the error variant to
CallContractError
, and the result to (bool, Option<A>)
.
If the result is Ok
then the boolean indicates whether the state was
modified or not, and the second item is the actual return value, which is
present (i.e., Some
) if and only if a V1
contract was invoked.HashMap
from hashbrown
with the default hasher set to
the fnv
hash function.HashSet
from hashbrown
with the default hasher set to
the fnv
hash function.Serial
instance.Result
that fixes the error variant to
QueryAccountBalanceError
and result to AccountBalance
.Result
that fixes the error variant to
QueryContractBalanceError
and result to Amount
.Result
that fixes the error variant to
CallContractError
, and the result to Option<A>
If the result is Ok
then the value is None
if a V0
contract was
invoked, and a return value returned by a V1
contract otherwise.Attribute Macros
wasm-test
feature of concordium-std
is enabled ignore the item,
this usually happens when executing tests with cargo-concordium
utility.
Otherwise this is equivalent to #[cfg(not(test))]
. Use as a dual to
#[concordium_cfg_test]
.#[test]
.Derive Macros
derive(Deletable)
for details and limitations.derive(Serial)
for details and limitations.derive(Deserial)
for details and limitations.SchemaType
trait for a type.
If the feature build-schema
is not enabled this is a no-op, i.e., it does
not produce any code.[derive(Serialize)]
is equivalent to [derive(Serial, Deserial)]
, see
documentation of the latter two for details and options:
derive(Serial)
,
derive(Deserial)
.derive(StateClone)
for details and
limitations.