pallet_contracts/chain_extension.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! A mechanism for runtime authors to augment the functionality of contracts.
19//!
20//! The runtime is able to call into any contract and retrieve the result using
21//! [`bare_call`](crate::Pallet::bare_call). This already allows customization of runtime
22//! behaviour by user generated code (contracts). However, often it is more straightforward
23//! to allow the reverse behaviour: The contract calls into the runtime. We call the latter
24//! one a "chain extension" because it allows the chain to extend the set of functions that are
25//! callable by a contract.
26//!
27//! In order to create a chain extension the runtime author implements the [`ChainExtension`]
28//! trait and declares it in this pallet's [configuration Trait](crate::Config). All types
29//! required for this endeavour are defined or re-exported in this module. There is an
30//! implementation on `()` which can be used to signal that no chain extension is available.
31//!
32//! # Using multiple chain extensions
33//!
34//! Often there is a need for having multiple chain extensions. This is often the case when
35//! some generally useful off-the-shelf extensions should be included. To have multiple chain
36//! extensions they can be put into a tuple which is then passed to [`Config::ChainExtension`] like
37//! this `type Extensions = (ExtensionA, ExtensionB)`.
38//!
39//! However, only extensions implementing [`RegisteredChainExtension`] can be put into a tuple.
40//! This is because the [`RegisteredChainExtension::ID`] is used to decide which of those extensions
41//! should be used when the contract calls a chain extensions. Extensions which are generally
42//! useful should claim their `ID` with [the registry](https://github.com/paritytech/chainextension-registry)
43//! so that no collisions with other vendors will occur.
44//!
45//! **Chain specific extensions must use the reserved `ID = 0` so that they can't be registered with
46//! the registry.**
47//!
48//! # Security
49//!
50//! The chain author alone is responsible for the security of the chain extension.
51//! This includes avoiding the exposure of exploitable functions and charging the
52//! appropriate amount of weight. In order to do so benchmarks must be written and the
53//! [`charge_weight`](Environment::charge_weight) function must be called **before**
54//! carrying out any action that causes the consumption of the chargeable weight.
55//! It cannot be overstated how delicate of a process the creation of a chain extension
56//! is. Check whether using [`bare_call`](crate::Pallet::bare_call) suffices for the
57//! use case at hand.
58//!
59//! # Benchmarking
60//!
61//! The builtin contract callable functions that pallet-contracts provides all have
62//! benchmarks that determine the correct weight that an invocation of these functions
63//! induces. In order to be able to charge the correct weight for the functions defined
64//! by a chain extension benchmarks must be written, too. In the near future this crate
65//! will provide the means for easier creation of those specialized benchmarks.
66//!
67//! # Example
68//!
69//! The ink-examples repository maintains an
70//! [end-to-end example](https://github.com/paritytech/ink-examples/tree/main/rand-extension)
71//! on how to use a chain extension in order to provide new features to ink! contracts.
72
73use crate::{
74 wasm::{Runtime, RuntimeCosts},
75 Error,
76};
77use alloc::vec::Vec;
78use codec::{Decode, MaxEncodedLen};
79use core::marker::PhantomData;
80use frame_support::weights::Weight;
81use sp_runtime::DispatchError;
82
83pub use crate::{exec::Ext, gas::ChargedAmount, storage::meter::Diff, Config};
84pub use frame_system::Config as SysConfig;
85pub use pallet_contracts_uapi::ReturnFlags;
86
87/// Result that returns a [`DispatchError`] on error.
88pub type Result<T> = core::result::Result<T, DispatchError>;
89
90/// A trait used to extend the set of contract callable functions.
91///
92/// In order to create a custom chain extension this trait must be implemented and supplied
93/// to the pallet contracts configuration trait as the associated type of the same name.
94/// Consult the [module documentation](self) for a general explanation of chain extensions.
95///
96/// # Lifetime
97///
98/// The extension will be [`Default`] initialized at the beginning of each call
99/// (**not** per call stack) and dropped afterwards. Hence any value held inside the extension
100/// can be used as a per-call scratch buffer.
101pub trait ChainExtension<C: Config> {
102 /// Call the chain extension logic.
103 ///
104 /// This is the only function that needs to be implemented in order to write a
105 /// chain extensions. It is called whenever a contract calls the `seal_call_chain_extension`
106 /// imported wasm function.
107 ///
108 /// # Parameters
109 /// - `env`: Access to the remaining arguments and the execution environment.
110 ///
111 /// # Return
112 ///
113 /// In case of `Err` the contract execution is immediately suspended and the passed error
114 /// is returned to the caller. Otherwise the value of [`RetVal`] determines the exit
115 /// behaviour.
116 ///
117 /// # Note
118 ///
119 /// The [`Self::call`] can be invoked within a read-only context, where any state-changing calls
120 /// are disallowed. This information can be obtained using `env.ext().is_read_only()`. It is
121 /// crucial for the implementer to handle this scenario appropriately.
122 fn call<E: Ext<T = C>>(&mut self, env: Environment<E, InitState>) -> Result<RetVal>;
123
124 /// Determines whether chain extensions are enabled for this chain.
125 ///
126 /// The default implementation returns `true`. Therefore it is not necessary to overwrite
127 /// this function when implementing a chain extension. In case of `false` the deployment of
128 /// a contract that references `seal_call_chain_extension` will be denied and calling this
129 /// function will return [`NoChainExtension`](Error::NoChainExtension) without first calling
130 /// into [`call`](Self::call).
131 fn enabled() -> bool {
132 true
133 }
134}
135
136/// A [`ChainExtension`] that can be composed with other extensions using a tuple.
137///
138/// An extension that implements this trait can be put in a tuple in order to have multiple
139/// extensions available. The tuple implementation routes requests based on the first two
140/// most significant bytes of the `id` passed to `call`.
141///
142/// If this extensions is to be used by multiple runtimes consider
143/// [registering it](https://github.com/paritytech/chainextension-registry) to ensure that there
144/// are no collisions with other vendors.
145///
146/// # Note
147///
148/// Currently, we support tuples of up to ten registered chain extensions. If more chain extensions
149/// are needed consider opening an issue.
150pub trait RegisteredChainExtension<C: Config>: ChainExtension<C> {
151 /// The extensions globally unique identifier.
152 const ID: u16;
153}
154
155#[impl_trait_for_tuples::impl_for_tuples(10)]
156#[tuple_types_custom_trait_bound(RegisteredChainExtension<C>)]
157impl<C: Config> ChainExtension<C> for Tuple {
158 fn call<E: Ext<T = C>>(&mut self, mut env: Environment<E, InitState>) -> Result<RetVal> {
159 for_tuples!(
160 #(
161 if (Tuple::ID == env.ext_id()) && Tuple::enabled() {
162 return Tuple.call(env);
163 }
164 )*
165 );
166 Err(Error::<E::T>::NoChainExtension.into())
167 }
168
169 fn enabled() -> bool {
170 for_tuples!(
171 #(
172 if Tuple::enabled() {
173 return true;
174 }
175 )*
176 );
177 false
178 }
179}
180
181/// Determines the exit behaviour and return value of a chain extension.
182pub enum RetVal {
183 /// The chain extensions returns the supplied value to its calling contract.
184 Converging(u32),
185 /// The control does **not** return to the calling contract.
186 ///
187 /// Use this to stop the execution of the contract when the chain extension returns.
188 /// The semantic is the same as for calling `seal_return`: The control returns to
189 /// the caller of the currently executing contract yielding the supplied buffer and
190 /// flags.
191 Diverging { flags: ReturnFlags, data: Vec<u8> },
192}
193
194/// Grants the chain extension access to its parameters and execution environment.
195///
196/// It uses [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html)
197/// to enforce the correct usage of the parameters passed to the chain extension.
198pub struct Environment<'a, 'b, E: Ext, S: State> {
199 /// The actual data of this type.
200 inner: Inner<'a, 'b, E>,
201 /// `S` is only used in the type system but never as value.
202 phantom: PhantomData<S>,
203}
204
205/// Functions that are available in every state of this type.
206impl<'a, 'b, E: Ext, S: State> Environment<'a, 'b, E, S> {
207 /// The function id within the `id` passed by a contract.
208 ///
209 /// It returns the two least significant bytes of the `id` passed by a contract as the other
210 /// two bytes represent the chain extension itself (the code which is calling this function).
211 pub fn func_id(&self) -> u16 {
212 (self.inner.id & 0x0000FFFF) as u16
213 }
214
215 /// The chain extension id within the `id` passed by a contract.
216 ///
217 /// It returns the two most significant bytes of the `id` passed by a contract which represent
218 /// the chain extension itself (the code which is calling this function).
219 pub fn ext_id(&self) -> u16 {
220 (self.inner.id >> 16) as u16
221 }
222
223 /// Charge the passed `amount` of weight from the overall limit.
224 ///
225 /// It returns `Ok` when there the remaining weight budget is larger than the passed
226 /// `weight`. It returns `Err` otherwise. In this case the chain extension should
227 /// abort the execution and pass through the error.
228 ///
229 /// The returned value can be used to with [`Self::adjust_weight`]. Other than that
230 /// it has no purpose.
231 ///
232 /// # Note
233 ///
234 /// Weight is synonymous with gas in substrate.
235 pub fn charge_weight(&mut self, amount: Weight) -> Result<ChargedAmount> {
236 self.inner.runtime.charge_gas(RuntimeCosts::ChainExtension(amount))
237 }
238
239 /// Adjust a previously charged amount down to its actual amount.
240 ///
241 /// This is when a maximum a priori amount was charged and then should be partially
242 /// refunded to match the actual amount.
243 pub fn adjust_weight(&mut self, charged: ChargedAmount, actual_weight: Weight) {
244 self.inner
245 .runtime
246 .adjust_gas(charged, RuntimeCosts::ChainExtension(actual_weight))
247 }
248
249 /// Grants access to the execution environment of the current contract call.
250 ///
251 /// Consult the functions on the returned type before re-implementing those functions.
252 pub fn ext(&mut self) -> &mut E {
253 self.inner.runtime.ext()
254 }
255}
256
257/// Functions that are only available in the initial state of this type.
258///
259/// Those are the functions that determine how the arguments to the chain extensions
260/// should be consumed.
261impl<'a, 'b, E: Ext> Environment<'a, 'b, E, InitState> {
262 /// Creates a new environment for consumption by a chain extension.
263 ///
264 /// It is only available to this crate because only the wasm runtime module needs to
265 /// ever create this type. Chain extensions merely consume it.
266 pub(crate) fn new(
267 runtime: &'a mut Runtime<'b, E>,
268 memory: &'a mut [u8],
269 id: u32,
270 input_ptr: u32,
271 input_len: u32,
272 output_ptr: u32,
273 output_len_ptr: u32,
274 ) -> Self {
275 Environment {
276 inner: Inner { runtime, memory, id, input_ptr, input_len, output_ptr, output_len_ptr },
277 phantom: PhantomData,
278 }
279 }
280
281 /// Use all arguments as integer values.
282 pub fn only_in(self) -> Environment<'a, 'b, E, OnlyInState> {
283 Environment { inner: self.inner, phantom: PhantomData }
284 }
285
286 /// Use input arguments as integer and output arguments as pointer to a buffer.
287 pub fn prim_in_buf_out(self) -> Environment<'a, 'b, E, PrimInBufOutState> {
288 Environment { inner: self.inner, phantom: PhantomData }
289 }
290
291 /// Use input and output arguments as pointers to a buffer.
292 pub fn buf_in_buf_out(self) -> Environment<'a, 'b, E, BufInBufOutState> {
293 Environment { inner: self.inner, phantom: PhantomData }
294 }
295}
296
297/// Functions to use the input arguments as integers.
298impl<'a, 'b, E: Ext, S: PrimIn> Environment<'a, 'b, E, S> {
299 /// The `input_ptr` argument.
300 pub fn val0(&self) -> u32 {
301 self.inner.input_ptr
302 }
303
304 /// The `input_len` argument.
305 pub fn val1(&self) -> u32 {
306 self.inner.input_len
307 }
308}
309
310/// Functions to use the output arguments as integers.
311impl<'a, 'b, E: Ext, S: PrimOut> Environment<'a, 'b, E, S> {
312 /// The `output_ptr` argument.
313 pub fn val2(&self) -> u32 {
314 self.inner.output_ptr
315 }
316
317 /// The `output_len_ptr` argument.
318 pub fn val3(&self) -> u32 {
319 self.inner.output_len_ptr
320 }
321}
322
323/// Functions to use the input arguments as pointer to a buffer.
324impl<'a, 'b, E: Ext, S: BufIn> Environment<'a, 'b, E, S> {
325 /// Reads `min(max_len, in_len)` from contract memory.
326 ///
327 /// This does **not** charge any weight. The caller must make sure that the an
328 /// appropriate amount of weight is charged **before** reading from contract memory.
329 /// The reason for that is that usually the costs for reading data and processing
330 /// said data cannot be separated in a benchmark. Therefore a chain extension would
331 /// charge the overall costs either using `max_len` (worst case approximation) or using
332 /// [`in_len()`](Self::in_len).
333 pub fn read(&self, max_len: u32) -> Result<Vec<u8>> {
334 self.inner.runtime.read_sandbox_memory(
335 self.inner.memory,
336 self.inner.input_ptr,
337 self.inner.input_len.min(max_len),
338 )
339 }
340
341 /// Reads `min(buffer.len(), in_len) from contract memory.
342 ///
343 /// This takes a mutable pointer to a buffer fills it with data and shrinks it to
344 /// the size of the actual data. Apart from supporting pre-allocated buffers it is
345 /// equivalent to to [`read()`](Self::read).
346 pub fn read_into(&self, buffer: &mut &mut [u8]) -> Result<()> {
347 let len = buffer.len();
348 let sliced = {
349 let buffer = core::mem::take(buffer);
350 &mut buffer[..len.min(self.inner.input_len as usize)]
351 };
352 self.inner.runtime.read_sandbox_memory_into_buf(
353 self.inner.memory,
354 self.inner.input_ptr,
355 sliced,
356 )?;
357 *buffer = sliced;
358 Ok(())
359 }
360
361 /// Reads and decodes a type with a size fixed at compile time from contract memory.
362 ///
363 /// This function is secure and recommended for all input types of fixed size
364 /// as long as the cost of reading the memory is included in the overall already charged
365 /// weight of the chain extension. This should usually be the case when fixed input types
366 /// are used.
367 pub fn read_as<T: Decode + MaxEncodedLen>(&mut self) -> Result<T> {
368 self.inner
369 .runtime
370 .read_sandbox_memory_as(self.inner.memory, self.inner.input_ptr)
371 }
372
373 /// Reads and decodes a type with a dynamic size from contract memory.
374 ///
375 /// Make sure to include `len` in your weight calculations.
376 pub fn read_as_unbounded<T: Decode>(&mut self, len: u32) -> Result<T> {
377 self.inner.runtime.read_sandbox_memory_as_unbounded(
378 self.inner.memory,
379 self.inner.input_ptr,
380 len,
381 )
382 }
383
384 /// The length of the input as passed in as `input_len`.
385 ///
386 /// A chain extension would use this value to calculate the dynamic part of its
387 /// weight. For example a chain extension that calculates the hash of some passed in
388 /// bytes would use `in_len` to charge the costs of hashing that amount of bytes.
389 /// This also subsumes the act of copying those bytes as a benchmarks measures both.
390 pub fn in_len(&self) -> u32 {
391 self.inner.input_len
392 }
393}
394
395/// Functions to use the output arguments as pointer to a buffer.
396impl<'a, 'b, E: Ext, S: BufOut> Environment<'a, 'b, E, S> {
397 /// Write the supplied buffer to contract memory.
398 ///
399 /// If the contract supplied buffer is smaller than the passed `buffer` an `Err` is returned.
400 /// If `allow_skip` is set to true the contract is allowed to skip the copying of the buffer
401 /// by supplying the guard value of `pallet-contracts::SENTINEL` as `out_ptr`. The
402 /// `weight_per_byte` is only charged when the write actually happens and is not skipped or
403 /// failed due to a too small output buffer.
404 pub fn write(
405 &mut self,
406 buffer: &[u8],
407 allow_skip: bool,
408 weight_per_byte: Option<Weight>,
409 ) -> Result<()> {
410 self.inner.runtime.write_sandbox_output(
411 self.inner.memory,
412 self.inner.output_ptr,
413 self.inner.output_len_ptr,
414 buffer,
415 allow_skip,
416 |len| {
417 weight_per_byte.map(|w| RuntimeCosts::ChainExtension(w.saturating_mul(len.into())))
418 },
419 )
420 }
421}
422
423/// The actual data of an `Environment`.
424///
425/// All data is put into this struct to easily pass it around as part of the typestate
426/// pattern. Also it creates the opportunity to box this struct in the future in case it
427/// gets too large.
428struct Inner<'a, 'b, E: Ext> {
429 /// The runtime contains all necessary functions to interact with the running contract.
430 runtime: &'a mut Runtime<'b, E>,
431 /// Reference to the contracts memory.
432 memory: &'a mut [u8],
433 /// Verbatim argument passed to `seal_call_chain_extension`.
434 id: u32,
435 /// Verbatim argument passed to `seal_call_chain_extension`.
436 input_ptr: u32,
437 /// Verbatim argument passed to `seal_call_chain_extension`.
438 input_len: u32,
439 /// Verbatim argument passed to `seal_call_chain_extension`.
440 output_ptr: u32,
441 /// Verbatim argument passed to `seal_call_chain_extension`.
442 output_len_ptr: u32,
443}
444
445/// Any state of an [`Environment`] implements this trait.
446/// See [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html).
447pub trait State: sealed::Sealed {}
448
449/// A state that uses primitive inputs.
450pub trait PrimIn: State {}
451
452/// A state that uses primitive outputs.
453pub trait PrimOut: State {}
454
455/// A state that uses a buffer as input.
456pub trait BufIn: State {}
457
458/// A state that uses a buffer as output.
459pub trait BufOut: State {}
460
461/// The initial state of an [`Environment`].
462pub enum InitState {}
463
464/// A state that uses all arguments as primitive inputs.
465pub enum OnlyInState {}
466
467/// A state that uses two arguments as primitive inputs and the other two as buffer output.
468pub enum PrimInBufOutState {}
469
470/// Uses a buffer for input and a buffer for output.
471pub enum BufInBufOutState {}
472
473mod sealed {
474 use super::*;
475
476 /// Trait to prevent users from implementing `State` for anything else.
477 pub trait Sealed {}
478
479 impl Sealed for InitState {}
480 impl Sealed for OnlyInState {}
481 impl Sealed for PrimInBufOutState {}
482 impl Sealed for BufInBufOutState {}
483
484 impl State for InitState {}
485 impl State for OnlyInState {}
486 impl State for PrimInBufOutState {}
487 impl State for BufInBufOutState {}
488
489 impl PrimIn for OnlyInState {}
490 impl PrimOut for OnlyInState {}
491 impl PrimIn for PrimInBufOutState {}
492 impl BufOut for PrimInBufOutState {}
493 impl BufIn for BufInBufOutState {}
494 impl BufOut for BufInBufOutState {}
495}