Module pallet_contracts::chain_extension
source · Expand description
A mechanism for runtime authors to augment the functionality of contracts.
The runtime is able to call into any contract and retrieve the result using
bare_call
. This already allows customization of runtime
behaviour by user generated code (contracts). However, often it is more straightforward
to allow the reverse behaviour: The contract calls into the runtime. We call the latter
one a “chain extension” because it allows the chain to extend the set of functions that are
callable by a contract.
In order to create a chain extension the runtime author implements the ChainExtension
trait and declares it in this pallet’s configuration Trait. All types
required for this endeavour are defined or re-exported in this module. There is an
implementation on ()
which can be used to signal that no chain extension is available.
Using multiple chain extensions
Often there is a need for having multiple chain extensions. This is often the case when
some generally useful off-the-shelf extensions should be included. To have multiple chain
extensions they can be put into a tuple which is then passed to Config::ChainExtension
like
this type Extensions = (ExtensionA, ExtensionB)
.
However, only extensions implementing RegisteredChainExtension
can be put into a tuple.
This is because the RegisteredChainExtension::ID
is used to decide which of those extensions
should be used when the contract calls a chain extensions. Extensions which are generally
useful should claim their ID
with the registry
so that no collisions with other vendors will occur.
Chain specific extensions must use the reserved ID = 0
so that they can’t be registered with
the registry.
Security
The chain author alone is responsible for the security of the chain extension.
This includes avoiding the exposure of exploitable functions and charging the
appropriate amount of weight. In order to do so benchmarks must be written and the
charge_weight
function must be called before
carrying out any action that causes the consumption of the chargeable weight.
It cannot be overstated how delicate of a process the creation of a chain extension
is. Check whether using bare_call
suffices for the
use case at hand.
Benchmarking
The builtin contract callable functions that pallet-contracts provides all have benchmarks that determine the correct weight that an invocation of these functions induces. In order to be able to charge the correct weight for the functions defined by a chain extension benchmarks must be written, too. In the near future this crate will provide the means for easier creation of those specialized benchmarks.
Example
The ink-examples repository maintains an end-to-end example on how to use a chain extension in order to provide new features to ink! contracts.
Re-exports
pub use crate::Config;
Structs
- This type is used to describe a storage change when charging from the meter.
- Grants the chain extension access to its parameters and execution environment.
- Flags used by a contract to customize exit behaviour.
Enums
- Uses a buffer for input and a buffer for output.
- The initial state of an
Environment
. - A state that uses all arguments as primitive inputs.
- A state that uses two arguments as primitive inputs and the other two as buffer output.
- Determines the exit behaviour and return value of a chain extension.
Traits
- A state that uses a buffer as input.
- A state that uses a buffer as output.
- A trait used to extend the set of contract callable functions.
- An interface that provides access to the external environment in which the smart-contract is executed.
- A state that uses primitive inputs.
- A state that uses primitive outputs.
- A
ChainExtension
that can be composed with other extensions using a tuple. - Any state of an
Environment
implements this trait. See typestate programming. - Configuration trait of this pallet.
Type Definitions
- Result that returns a
DispatchError
on error.