Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1c48304
Add precompiles
athei Apr 11, 2025
0e83666
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Apr 16, 2025
782894b
Update from github-actions[bot] running command 'bench --runtime dev …
github-actions[bot] Apr 16, 2025
5fbd52b
Fix benchmarks
athei Apr 16, 2025
9514d33
Clippy
athei Apr 16, 2025
fa515d5
Update from github-actions[bot] running command 'bench --runtime dev …
github-actions[bot] Apr 16, 2025
c36172d
Use new weight values
athei Apr 16, 2025
7eb7143
Update penpal runtime
athei Apr 16, 2025
c551aa5
Fix docs
athei Apr 17, 2025
f121424
Fix tests
athei Apr 22, 2025
0811818
Don't export macros from crate and add some docs
athei Apr 22, 2025
4d5e4a5
Add `run::precompile`
athei Apr 22, 2025
85e1180
Add more docs
athei Apr 22, 2025
bec4ea9
Zero out output buffer len on error
athei Apr 23, 2025
9687819
Add more tests for pre-compiles
athei Apr 22, 2025
57856c4
Merge branch 'master' into at/precompiles
athei Apr 23, 2025
f0c95b7
Apply suggestions from code review
athei Apr 23, 2025
3ecb05b
Apply suggestions from code review
athei Apr 24, 2025
796c388
Merge branch 'master' into at/precompiles
athei Apr 24, 2025
7cdfacd
Fix some docs
athei Apr 24, 2025
6ee9355
Port over disabled test to precompiles
athei Apr 24, 2025
f3bb252
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Apr 24, 2025
6836858
Update from github-actions[bot] running command 'prdoc --audience run…
github-actions[bot] Apr 24, 2025
379335f
Apply suggestions from code review
athei Apr 25, 2025
62db3dc
Merge branch 'master' into at/precompiles
athei Apr 25, 2025
23c3ed2
Only charge execution from the nested meter
athei Apr 28, 2025
47149b2
Merge branch 'master' into at/precompiles
athei Apr 28, 2025
863c4da
Disable broken test
athei Apr 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ impl pallet_revive::Config for Runtime {
type DepositPerByte = DepositPerByte;
type WeightPrice = pallet_transaction_payment::Pallet<Self>;
type WeightInfo = pallet_revive::weights::SubstrateWeight<Self>;
type ChainExtension = ();
type Precompiles = ();
type AddressMapper = pallet_revive::AccountId32Mapper<Self>;
type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
Expand Down
2 changes: 1 addition & 1 deletion cumulus/parachains/runtimes/testing/penpal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ impl pallet_revive::Config for Runtime {
type DepositPerByte = DepositPerByte;
type WeightPrice = pallet_transaction_payment::Pallet<Self>;
type WeightInfo = pallet_revive::weights::SubstrateWeight<Self>;
type ChainExtension = ();
type Precompiles = ();
type AddressMapper = pallet_revive::AccountId32Mapper<Self>;
type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
Expand Down
33 changes: 33 additions & 0 deletions prdoc/pr_8262.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
title: 'pallet_revive: Replace adhoc pre-compiles with pre-compile framework'
doc:
- audience: Runtime Dev
description: |-
This PRs adds the ability to define custom pre-compiles from outside the pallet. Before, all pre-compiles were hard coded as part of the pallet.

## Design
1. Adding a pre-compile is as easy as implementing the new `Precompile` trait on any type. It can be added to the pallet by passing it into `Config::Precompiles`. This config know excepts a tuple of multiple types that each implement `Precompile`.
2. Each pre-compile has to implement Solidity ABI. Meaning its inputs and outputs are encoded according to Eth ABI. This makes writing a pre-compile much simpler since it doesn't have to implement its own decoding logic. More importantly: It makes it trivial to consume the API from a Solidity contract.
3. We constrain the address space of pre-compiles to a safe range so that they cannot accidentally match a wide range creating a collision with real contracts.
4. We check that pre-compile address ranges do not overlap at compile time.
5. Pre-compiles behave exactly as a normal contract. They exist as frames on the call stack and the environment they observe is their own (not the one of the calling contract). They can also be delegate called which changes the semantics in the same way as for normal contracts: They observe the environment of the calling contract.
6. They can also be called by the origin without any other contract in-between.

Check the rustdocs of the `precompile` module on how to write a pre-compile.

## Changes
1. A new module `precompiles` is added that contains the framework to write pre-compiles. It also contains the sub module `builtin` that contains hard coded pre-compiles which exist Ethereum.
2. The `pure_precompiles` module was deleted since all its pre-compiles were ported over to the new framework and are now housed in `builtin`.
4. The `CallSetup` type is moved outside of the `benchmarking` module because it is also needed for testing code now. It is intended to be used for implementors outside of the crate to test the pre-compiles (in addition to benchmarking them).

## Follow Ups
- Enrich the `CallSetup` API with more functions in order to allow testing more complex scenarios. Should probably be done in tandem with writing the ERC20 pre-compile.
- The collision checks for pre-compile addresses are done at compile time. They need some `try_build` tests to make sure it works as intended.
crates:
- name: asset-hub-westend-runtime
bump: major
- name: pallet-revive
bump: major
- name: penpal-runtime
bump: major
- name: pallet-revive-fixtures
bump: major
2 changes: 1 addition & 1 deletion substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,7 @@ impl pallet_revive::Config for Runtime {
type DepositPerByte = DepositPerByte;
type WeightPrice = pallet_transaction_payment::Pallet<Self>;
type WeightInfo = pallet_revive::weights::SubstrateWeight<Self>;
type ChainExtension = ();
type Precompiles = ();
type AddressMapper = pallet_revive::AccountId32Mapper<Self>;
type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
Expand Down
1 change: 1 addition & 0 deletions substrate/frame/revive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ xcm-builder = { workspace = true }
[dev-dependencies]
array-bytes = { workspace = true, default-features = true }
assert_matches = { workspace = true }
polkavm-common = { version = "0.21.0" }
pretty_assertions = { workspace = true }
secp256k1 = { workspace = true, features = ["recovery"] }
serde_json = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This calls another contract and returns the returncode and output.

#![no_std]
#![no_main]
include!("../panic_handler.rs");

use uapi::{input, u256_bytes, HostFn, HostFnImpl as api};

#[no_mangle]
#[polkavm_derive::polkavm_export]
pub extern "C" fn deploy() {}

#[no_mangle]
#[polkavm_derive::polkavm_export]
pub extern "C" fn call() {
input!(
512,
callee_addr: &[u8; 20],
value: u64,
callee_input: [u8],
);

// the first 4 bytes are reserved for the return code
let mut output = [0u8; 512];
let output_ptr = &mut &mut output[4..];

let code = match api::call(
uapi::CallFlags::empty(),
callee_addr,
u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all.
u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all.
&[u8::MAX; 32], // No deposit limit.
&u256_bytes(value), // Value transferred to the contract.
callee_input,
Some(output_ptr),
) {
Ok(_) => 0,
Err(code) => code as u32,
};

let len = 4 + output_ptr.len();
output[0..4].copy_from_slice(&code.to_le_bytes());
api::return_value(uapi::ReturnFlags::empty(), &output[..len]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ pub extern "C" fn deploy() {}
pub extern "C" fn call() {
input!(address: &[u8; 20],);

let mut output = [0; 512];
let ptr = &mut &mut output[..];

// Delegate call into passed address.
let input = [0u8; 0];
api::delegate_call(
Expand All @@ -39,7 +42,9 @@ pub extern "C" fn call() {
u64::MAX,
&[u8::MAX; 32],
&input,
None,
Some(ptr),
)
.unwrap();

assert_eq!(ptr.len(), 0);
}
Loading
Loading