mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 11:41:04 +00:00
Dispatch Calls to other modules (#1473)
* WIP * Use system::Origin::Signed as an origin * Add a vm test for ext_dispatch_call * Take fee for dispatching a Call # Conflicts: # node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm * Clean & Rebuild # Conflicts: # node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm * Dispatch call test. * Rebuild the runtime. * Fix the length of the buffer. * Rebuild binaries.
This commit is contained in:
committed by
Gav Wood
parent
22b65c9cb0
commit
58cd6530be
@@ -174,12 +174,15 @@ mod tests {
|
||||
use std::collections::HashMap;
|
||||
use substrate_primitives::H256;
|
||||
use exec::{CallReceipt, Ext, InstantiateReceipt, EmptyOutputBuf};
|
||||
use balances;
|
||||
use gas::GasMeter;
|
||||
use tests::Test;
|
||||
use tests::{Test, Call};
|
||||
use wabt;
|
||||
use wasm::prepare::prepare_contract;
|
||||
use CodeHash;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct DispatchEntry(Call);
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct CreateEntry {
|
||||
code_hash: H256,
|
||||
@@ -199,6 +202,7 @@ mod tests {
|
||||
storage: HashMap<Vec<u8>, Vec<u8>>,
|
||||
creates: Vec<CreateEntry>,
|
||||
transfers: Vec<TransferEntry>,
|
||||
dispatches: Vec<DispatchEntry>,
|
||||
next_account_id: u64,
|
||||
}
|
||||
impl Ext for MockExt {
|
||||
@@ -248,6 +252,9 @@ mod tests {
|
||||
output_data: Vec::new(),
|
||||
})
|
||||
}
|
||||
fn note_dispatch_call(&mut self, call: Call) {
|
||||
self.dispatches.push(DispatchEntry(call));
|
||||
}
|
||||
fn caller(&self) -> &u64 {
|
||||
&42
|
||||
}
|
||||
@@ -942,6 +949,45 @@ mod tests {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
const CODE_DISPATCH_CALL: &str = r#"
|
||||
(module
|
||||
(import "env" "ext_dispatch_call" (func $ext_dispatch_call (param i32 i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
|
||||
(func (export "call")
|
||||
(call $ext_dispatch_call
|
||||
(i32.const 8) ;; Pointer to the start of encoded call buffer
|
||||
(i32.const 13) ;; Length of the buffer
|
||||
)
|
||||
)
|
||||
(func (export "deploy"))
|
||||
|
||||
(data (i32.const 8) "\00\01\2A\00\00\00\00\00\00\00\E5\14\00")
|
||||
)
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn dispatch_call() {
|
||||
// This test can fail due to the encoding changes. In case it becomes too annoying
|
||||
// let's rewrite so as we use this module controlled call or we serialize it in runtime.
|
||||
|
||||
let mut mock_ext = MockExt::default();
|
||||
execute(
|
||||
CODE_DISPATCH_CALL,
|
||||
&[],
|
||||
&mut Vec::new(),
|
||||
&mut mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
&mock_ext.dispatches,
|
||||
&[DispatchEntry(
|
||||
Call::Balances(balances::Call::set_balance(42, 1337.into(), 0.into())),
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
const CODE_RETURN_FROM_START_FN: &str = r#"
|
||||
(module
|
||||
|
||||
@@ -21,11 +21,11 @@ use exec::{Ext, BalanceOf, VmExecResult, OutputBuf, EmptyOutputBuf, CallReceipt,
|
||||
use rstd::prelude::*;
|
||||
use rstd::mem;
|
||||
use codec::{Decode, Encode};
|
||||
use gas::{GasMeter, Token, GasMeterResult};
|
||||
use gas::{GasMeter, Token, GasMeterResult, approx_gas_for_balance};
|
||||
use runtime_primitives::traits::{As, CheckedMul, Bounded};
|
||||
use sandbox;
|
||||
use system;
|
||||
use {Trait, CodeHash};
|
||||
use {Trait, CodeHash, ComputeDispatchFee};
|
||||
|
||||
/// Enumerates all possible *special* trap conditions.
|
||||
///
|
||||
@@ -96,7 +96,7 @@ pub(crate) fn to_execution_result<E: Ext>(
|
||||
|
||||
#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum RuntimeToken {
|
||||
pub enum RuntimeToken<Gas> {
|
||||
/// Explicit call to the `gas` function. Charge the gas meter
|
||||
/// with the value provided.
|
||||
Explicit(u32),
|
||||
@@ -107,9 +107,11 @@ pub enum RuntimeToken {
|
||||
/// The given number of bytes is read from the sandbox memory and
|
||||
/// is returned as the return data buffer of the call.
|
||||
ReturnData(u32),
|
||||
/// Dispatch fee calculated by `T::ComputeDispatchFee`.
|
||||
ComputedDispatchFee(Gas),
|
||||
}
|
||||
|
||||
impl<T: Trait> Token<T> for RuntimeToken {
|
||||
impl<T: Trait> Token<T> for RuntimeToken<T::Gas> {
|
||||
type Metadata = Schedule<T::Gas>;
|
||||
|
||||
fn calculate_amount(&self, metadata: &Schedule<T::Gas>) -> T::Gas {
|
||||
@@ -125,6 +127,7 @@ impl<T: Trait> Token<T> for RuntimeToken {
|
||||
ReturnData(byte_count) => metadata
|
||||
.return_data_per_byte_cost
|
||||
.checked_mul(&<T::Gas as As<u32>>::sa(byte_count)),
|
||||
ComputedDispatchFee(gas) => Some(gas),
|
||||
};
|
||||
|
||||
value.unwrap_or_else(|| Bounded::max_value())
|
||||
@@ -482,6 +485,30 @@ define_env!(Env, <E: Ext>,
|
||||
Ok(())
|
||||
},
|
||||
|
||||
// Decodes the given buffer as a `T::Call` and adds it to the list
|
||||
// of to-be-dispatched calls.
|
||||
//
|
||||
// All calls made it to the top-level context will be dispatched before
|
||||
// finishing the execution of the calling extrinsic.
|
||||
ext_dispatch_call(ctx, call_ptr: u32, call_len: u32) => {
|
||||
let call = {
|
||||
let call_buf = read_sandbox_memory(ctx, call_ptr, call_len)?;
|
||||
<<<E as Ext>::T as Trait>::Call>::decode(&mut &call_buf[..])
|
||||
.ok_or_else(|| sandbox::HostError)?
|
||||
};
|
||||
|
||||
// Charge gas for dispatching this call.
|
||||
let fee = {
|
||||
let balance_fee = <<E as Ext>::T as Trait>::ComputeDispatchFee::compute_dispatch_fee(&call);
|
||||
approx_gas_for_balance::<<E as Ext>::T>(ctx.gas_meter.gas_price(), balance_fee)
|
||||
};
|
||||
charge_gas(&mut ctx.gas_meter, ctx.schedule, RuntimeToken::ComputedDispatchFee(fee))?;
|
||||
|
||||
ctx.ext.note_dispatch_call(call);
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
||||
// Returns the size of the input buffer.
|
||||
ext_input_size(ctx) -> u32 => {
|
||||
Ok(ctx.input_data.len() as u32)
|
||||
|
||||
Reference in New Issue
Block a user