Skip to content
This repository has been archived by the owner on Sep 28, 2023. It is now read-only.

XVM gas handling prototype #94

Merged
merged 11 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ members = [
"precompiles/xcm",
"precompiles/xvm",

"contracts/*",
# Current build fails due to error associated with incorrect nightly usage
# but we use one from polkadot release so we probably shouldn't change it yet.
# "contracts/*",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unintentionally left edit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment.

It seems that after latest updates, compilation with cargo check fails.

cargo contract check should work but it also fails for me with another error so I'll have to check that in more detail.

Perhaps this also indicates that we shouldn't keep contracts under root .toml file 🤔

]
28 changes: 13 additions & 15 deletions chain-extensions/impls/xvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,19 @@ where

match func_id {
XvmFuncId::XvmCall => {
// TODO: correct weight calculation directly from pallet!
let weight = 1_000_000_000;
env.charge_weight(weight)?;
// 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 charged_weight = env.charge_weight(remaining_weight)?;

// Prepare parameters
let caller = env.ext().caller().clone();

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

// TODO: rethink this? How do we get valid env in chain extension? Need to know which data to encode.
// gas limit, taking into account used gas so far?
let _origin_address = env.ext().address().clone();
let _value = env.ext().value_transferred();
let _gas_limit = env.ext().gas_meter().gas_left();
let xvm_context = XvmContext {
id: vm_id,
max_weight: remaining_weight,
env: None,
};

Expand All @@ -77,9 +70,14 @@ where
input,
);

// TODO: We need to know how much of gas was spent in the other call and update the gas meter!
// let consumed_xvm_weight = ...;
// env.charge_weight(consumed_xvm_weight)?;
// Adjust the actual weight used by the call if needed.
let actual_weight = match call_result {
Ok(e) => e.actual_weight,
Err(e) => e.post_info.actual_weight,
};
if let Some(actual_weight) = actual_weight {
env.adjust_weight(charged_weight, actual_weight);
}

return match call_result {
Err(e) => {
Expand Down
8 changes: 2 additions & 6 deletions chain-extensions/types/xvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,15 @@ description = "Types definitions for contracts using xvm chain-extension."

[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.28", default-features = false }
ink_prelude = { version = "3", default-features = false }
scale-info = { version = "2.1.0", default-features = false, features = ["derive"] }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.28", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.28", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.28", default-features = false }

[features]
default = ["std"]
std = [
"codec/std",
"frame-support/std",
"scale-info/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"ink_prelude/std",
]
3 changes: 2 additions & 1 deletion chain-extensions/types/xvm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#![cfg_attr(not(feature = "std"), no_std)]

use codec::{Decode, Encode};
use ink_prelude::vec::Vec;
use sp_runtime::{DispatchError, ModuleError};
use sp_std::vec::Vec; // TODO use ink_prelude::vec::Vec; ?

#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Debug)]
Expand Down
27 changes: 16 additions & 11 deletions contracts/xvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ repository = "https://github.com/AstarNetwork/astar-frame"
description = "Chain extension for X-VM calls"

[dependencies]
ink_env = { version = "3", default-features = false }
ink_lang = { version = "3", default-features = false }
ink_metadata = { version = "3", default-features = false, features = ["derive"], optional = true }
ink_prelude = { version = "3", default-features = false }
ink_primitives = { version = "3", default-features = false }
ink_storage = { version = "3", default-features = false }
ink_env = { version = "3.3", default-features = false }
ink_lang = { version = "3.3", default-features = false }
ink_metadata = { version = "3.3", default-features = false, features = [
"derive",
], optional = true }
ink_prelude = { version = "3.3", default-features = false }
ink_primitives = { version = "3.3", default-features = false }
ink_storage = { version = "3.3", default-features = false }

scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false, features = ["derive"], optional = true }

xvm-chain-extension-types = { path = "../../chain-extensions/types/xvm", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = [
"derive",
] }
scale-info = { version = "2", default-features = false, features = [
"derive",
], optional = true }

[lib]
name = "xvm_chain_extension_contract"
name = "xvm_example"
path = "src/lib.rs"
crate-type = [
# Used for normal contract Wasm blobs.
Expand All @@ -36,6 +40,7 @@ std = [
"ink_env/std",
"ink_storage/std",
"ink_primitives/std",
"ink_prelude/std",
"scale/std",
"scale-info/std",
]
Expand Down
25 changes: 19 additions & 6 deletions contracts/xvm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
#![cfg_attr(not(feature = "std"), no_std)]

use ink_env::{DefaultEnvironment, Environment};
use ink_lang as ink;
use xvm_chain_extension_types::XvmCallArgs;

use ink_env::{DefaultEnvironment, Environment};
use ink_prelude::vec::Vec;

#[derive(Clone, PartialEq, Eq, scale::Encode, scale::Decode, Debug)]
pub struct XvmCallArgs {
/// virtual machine identifier
pub vm_id: u8,
/// Call destination (e.g. address)
pub to: Vec<u8>,
/// Encoded call params
pub input: Vec<u8>,
}

pub const FRONTIER_VM_ID: u8 = 0x0F;
pub const PARITY_WASM_VM_ID: u8 = 0x1F;

#[ink::chain_extension]
pub trait XvmChainExtension {
Expand Down Expand Up @@ -53,7 +67,7 @@ impl Environment for CustomEnvironment {
///
/// This will give us access to the chain extension that we've defined.
#[ink::contract(env = crate::CustomEnvironment)]
mod xvm_chain_extension_contract {
mod xvm_example {

use super::*;
use scale::Encode;
Expand All @@ -72,10 +86,9 @@ mod xvm_chain_extension_contract {
self.env()
.extension()
.xvm_call(XvmCallArgs {
vm_id: xvm_chain_extension_types::FRONTIER_VM_ID,
to: address.encode(), // TODO: is this correct?
vm_id: FRONTIER_VM_ID,
to: address.encode(),
input: Default::default(),
metadata: Default::default(),
})
.map_err(|_| ExtensionError::XvmCallFailed)?;

Expand Down
35 changes: 21 additions & 14 deletions frame/pallet-xvm/src/evm.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! EVM support for XVM pallet.

use crate::*;
use pallet_evm::GasWeightMapping;
use sp_core::{H160, U256};
use sp_runtime::traits::Get;

Expand All @@ -19,22 +20,22 @@ where
I::get()
}

fn xvm_call(
_context: XvmContext<VmId>,
from: T::AccountId,
to: Vec<u8>,
input: Vec<u8>,
) -> Result<Vec<u8>, Vec<u8>> {
fn xvm_call(context: XvmContext, from: T::AccountId, to: Vec<u8>, input: Vec<u8>) -> XvmResult {
log::trace!(
target: "xvm::EVM::xvm_call",
"Start EVM XVM: {:?}, {:?}, {:?}, {:?}",
from, to, input, metadata,
"Start EVM XVM: {:?}, {:?}, {:?}",
from, to, input,
);
let value = U256::from(0u64);
let max_fee_per_gas = U256::from(3450898690u64);
let gas_limit = 4000000u64;
let evm_to: H160 = Decode::decode(&mut to.as_ref())
.map_err(|_| b"`to` argument decode failure".to_vec())?;
let gas_limit = T::GasWeightMapping::weight_to_gas(context.max_weight);
log::trace!(
target: "xvm::EVM::xvm_call",
"EVM xvm call gas limit: {:?} or as weight: {:?}", gas_limit, context.max_weight);
let evm_to = Decode::decode(&mut to.as_ref()).map_err(|_| XvmCallError {
error: XvmError::EncodingFailure,
consumed_weight: PLACEHOLDER_WEIGHT,
})?;

let res = pallet_evm::Pallet::<T>::call(
frame_support::dispatch::RawOrigin::Root.into(),
Expand All @@ -47,14 +48,20 @@ where
None,
None,
Vec::new(),
);
)
.map_err(|e| XvmCallError {
error: XvmError::ExecutionError(Vec::default()), // TODO: make error mapping make more sense
consumed_weight: e.post_info.actual_weight.unwrap_or(context.max_weight),
})?;

log::trace!(
target: "xvm::EVM::xvm_call",
"EVM XVM call result: {:?}", res
);

// TODO: return result or error if call failure
Ok(Default::default())
Ok(XvmCallOk {
output: Default::default(), // TODO: Fill output vec with response from the call
consumed_weight: res.actual_weight.unwrap_or(context.max_weight),
})
}
}
Loading