Skip to content

Commit

Permalink
pallet-xvm refactor (#980)
Browse files Browse the repository at this point in the history
* pallet-xvm refactor.

* Add TODOs.

* Update design.

* Keep XVM call interface unified.

* Renaming.

* update & integration.

* Update xvm precompiles mock & tests.

* Replace 'UnknownError' with concrete errors.

* Update CE & precompile.

* Clean up.

* Benchmarks and mock.

* Updates for polkadot-v0.9.43.

* Fix benchmarks.

* Add benchmarking result and weight info.

* Add license header to weight.rs.

* Add pallet description docstring.

* Record gas cost in XVM precompile.

* Less weight is available with overheads cost.

* Trace Ethereum transact result.

* Handle record cost result.

* Bump Shibuya semver and spec versoin.

* Apply review suggestions.

* Update with new benchmarking result.

* Improve XVM call benchmarking.

* Make local/shibuya/shiden/astar runtimes and client have the same semver.

* Update with new benchmarking result.
  • Loading branch information
shaunxw authored Jul 28, 2023
1 parent 53500c1 commit 18ff2b9
Show file tree
Hide file tree
Showing 34 changed files with 1,013 additions and 752 deletions.
28 changes: 16 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ pallet-collator-selection = { path = "./pallets/collator-selection", default-fea
pallet-custom-signatures = { path = "./pallets/custom-signatures", default-features = false }
pallet-dapps-staking = { path = "./pallets/dapps-staking", default-features = false }
pallet-xc-asset-config = { path = "./pallets/xc-asset-config", default-features = false }
pallet-xvm = { path = "./pallets/pallet-xvm", default-features = false }
pallet-xvm = { path = "./pallets/xvm", default-features = false }
pallet-xcm = { path = "./pallets/pallet-xcm", default-features = false }
pallet-ethereum-checked = { path = "./pallets/ethereum-checked", default-features = false }

Expand Down
2 changes: 1 addition & 1 deletion bin/collator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "astar-collator"
version = "5.15.0"
version = "5.16.0"
description = "Astar collator implementation in Rust."
build = "build.rs"
default-run = "astar-collator"
Expand Down
2 changes: 2 additions & 0 deletions chain-extensions/types/xvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ homepage.workspace = true
repository.workspace = true

[dependencies]
astar-primitives = { workspace = true }
parity-scale-codec = { workspace = true }
scale-info = { workspace = true }
sp-runtime = { workspace = true }
Expand All @@ -21,4 +22,5 @@ std = [
"scale-info/std",
"sp-runtime/std",
"sp-std/std",
"astar-primitives/std",
]
40 changes: 24 additions & 16 deletions chain-extensions/types/xvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,42 @@

#![cfg_attr(not(feature = "std"), no_std)]

use astar_primitives::xvm::CallError;
use parity_scale_codec::{Decode, Encode};
use sp_runtime::{DispatchError, ModuleError};
use sp_std::vec::Vec;

#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Debug)]
pub enum XvmExecutionResult {
/// Success
Success = 0,
// TODO: expand this with concrete XVM errors
/// Error not (yet) covered by a dedidacted code
UnknownError = 255,
Ok,
/// Failure
Err(u32),
}

impl TryFrom<DispatchError> for XvmExecutionResult {
type Error = DispatchError;
impl From<CallError> for XvmExecutionResult {
fn from(input: CallError) -> Self {
use CallError::*;

fn try_from(input: DispatchError) -> Result<Self, Self::Error> {
let _error_text = match input {
DispatchError::Module(ModuleError { message, .. }) => message,
_ => Some("No module error Info"),
// `0` is reserved for `Ok`
let error_code = match input {
InvalidVmId => 1,
SameVmCallNotAllowed => 2,
InvalidTarget => 3,
InputTooLarge => 4,
BadOrigin => 5,
ExecutionFailed(_) => 6,
};
Self::Err(error_code)
}
}

// TODO: expand this with concrete XVM errors (see dapps-staking types for example)
Ok(XvmExecutionResult::UnknownError)
impl From<XvmExecutionResult> for u32 {
fn from(input: XvmExecutionResult) -> Self {
match input {
XvmExecutionResult::Ok => 0,
XvmExecutionResult::Err(code) => code,
}
}
}

Expand All @@ -55,6 +66,3 @@ pub struct XvmCallArgs {
/// Encoded call params
pub input: Vec<u8>,
}

pub const FRONTIER_VM_ID: u8 = 0x0F;
pub const PARITY_WASM_VM_ID: u8 = 0x1F;
6 changes: 3 additions & 3 deletions chain-extensions/xvm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pallet-chain-extension-xvm"
version = "0.1.0"
version = "0.1.1"
license = "Apache-2.0"
description = "Chain extension for XVM"
authors.workspace = true
Expand All @@ -22,7 +22,7 @@ sp-runtime = { workspace = true }
sp-std = { workspace = true }

# Astar
pallet-xvm = { workspace = true }
astar-primitives = { workspace = true }
xvm-chain-extension-types = { workspace = true }

[features]
Expand All @@ -39,5 +39,5 @@ std = [
"sp-core/std",
"sp-runtime/std",
# Astar
"pallet-xvm/std",
"astar-primitives/std",
]
68 changes: 41 additions & 27 deletions chain-extensions/xvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@

#![cfg_attr(not(feature = "std"), no_std)]

use astar_primitives::xvm::{CallError, Context, VmId, XvmCall};
use frame_support::dispatch::Encode;
use pallet_contracts::{
chain_extension::{ChainExtension, Environment, Ext, InitState, RetVal},
Origin,
};
use pallet_xvm::XvmContext;
use sp_runtime::DispatchError;
use sp_std::marker::PhantomData;
use xvm_chain_extension_types::{XvmCallArgs, XvmExecutionResult};

enum XvmFuncId {
XvmCall,
Call,
// TODO: expand with other calls too
}

Expand All @@ -38,7 +38,7 @@ impl TryFrom<u16> for XvmFuncId {

fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
1 => Ok(XvmFuncId::XvmCall),
1 => Ok(XvmFuncId::Call),
_ => Err(DispatchError::Other(
"Unsupported func id in Xvm chain extension",
)),
Expand All @@ -47,17 +47,18 @@ impl TryFrom<u16> for XvmFuncId {
}

/// XVM chain extension.
pub struct XvmExtension<T>(PhantomData<T>);
pub struct XvmExtension<T, XC>(PhantomData<(T, XC)>);

impl<T> Default for XvmExtension<T> {
impl<T, XC> Default for XvmExtension<T, XC> {
fn default() -> Self {
XvmExtension(PhantomData)
}
}

impl<T> ChainExtension<T> for XvmExtension<T>
impl<T, XC> ChainExtension<T> for XvmExtension<T, XC>
where
T: pallet_contracts::Config + pallet_xvm::Config,
T: pallet_contracts::Config,
XC: XvmCall<T::AccountId>,
{
fn call<E: Ext>(&mut self, env: Environment<E, InitState>) -> Result<RetVal, DispatchError>
where
Expand All @@ -67,13 +68,13 @@ where
let mut env = env.buf_in_buf_out();

match func_id {
XvmFuncId::XvmCall => {
XvmFuncId::Call => {
// We need to immediately charge for the worst case scenario. Gas equals Weight in pallet-contracts context.
let remaining_weight = env.ext().gas_meter().gas_left();
let weight_limit = env.ext().gas_meter().gas_left();
// TODO: track proof size in align fees ticket
// We don't track used proof size, so we can't refund after.
// So we will charge a 32KB dummy value as a temporary replacement.
let charged_weight =
env.charge_weight(remaining_weight.set_proof_size(32 * 1024))?;
let charged_weight = env.charge_weight(weight_limit.set_proof_size(32 * 1024))?;

let caller = match env.ext().caller().clone() {
Origin::Signed(address) => address,
Expand All @@ -82,47 +83,60 @@ where
target: "xvm-extension::xvm_call",
"root origin not supported"
);
// TODO: expand XvmErrors with BadOrigin
return Ok(RetVal::Converging(XvmExecutionResult::UnknownError as u32));
return Ok(RetVal::Converging(
XvmExecutionResult::from(CallError::BadOrigin).into(),
));
}
};

let XvmCallArgs { vm_id, to, input } = env.read_as_unbounded(env.in_len())?;

let _origin_address = env.ext().address().clone();
let _value = env.ext().value_transferred();
let xvm_context = XvmContext {
id: vm_id,
max_weight: remaining_weight,
env: None,
let xvm_context = Context {
source_vm_id: VmId::Wasm,
weight_limit,
};

let call_result =
pallet_xvm::Pallet::<T>::xvm_bare_call(xvm_context, caller, to, input);
let vm_id = {
match TryInto::<VmId>::try_into(vm_id) {
Ok(id) => id,
Err(err) => {
// TODO: Propagate error
let result = Into::<XvmExecutionResult>::into(err);
return Ok(RetVal::Converging(result.into()));
}
}
};
let call_result = XC::call(xvm_context, vm_id, caller, to, input);

let actual_weight = pallet_xvm::consumed_weight(&call_result);
let actual_weight = match call_result {
Ok(ref info) => info.used_weight,
Err(ref err) => err.used_weight,
};
env.adjust_weight(charged_weight, actual_weight);

match call_result {
Ok(success) => {
Ok(info) => {
log::trace!(
target: "xvm-extension::xvm_call",
"success: {:?}", success
"info: {:?}", info
);

let buffer: sp_std::vec::Vec<_> = success.output().encode();
let buffer: sp_std::vec::Vec<_> = info.output.encode();
env.write(&buffer, false, None)?;
Ok(RetVal::Converging(XvmExecutionResult::Success as u32))
Ok(RetVal::Converging(XvmExecutionResult::Ok.into()))
}

Err(failure) => {
Err(err) => {
log::trace!(
target: "xvm-extension::xvm_call",
"failure: {:?}", failure
"err: {:?}", err
);

// TODO Propagate error
Ok(RetVal::Converging(XvmExecutionResult::UnknownError as u32))
let result = Into::<XvmExecutionResult>::into(err.error);
Ok(RetVal::Converging(result.into()))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion pallets/ethereum-checked/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
//!
//! ## Overview
//!
//! A `pallet-ethererum` like pallet that execute transactions from checked source,
//! A `pallet-ethereum like pallet that execute transactions from checked source,
//! like XCM remote call, cross-VM call, etc. Only `Call` transactions are supported
//! (no `Create`).
//!
Expand Down
Loading

0 comments on commit 18ff2b9

Please sign in to comment.