mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 23:47:56 +00:00
contracts: Move Schedule from Storage to Config (#8773)
* Move `Schedule` from Storage to Config * Updated CHANGELOG * Fix nits from review * Fix migration * Print the debug buffer as tracing message * Use `debug` instead of `trace` and update README * Add additional assert to test * Rename `schedule_version` to `instruction_weights_version` * Fixed typo * Added more comments to wat fixtures * Add clarification for the `debug_message` field
This commit is contained in:
committed by
GitHub
parent
3c0270fe57
commit
1ac95b6ba6
@@ -315,6 +315,16 @@ pub trait Ext: sealing::Sealed {
|
||||
|
||||
/// Get a mutable reference to the nested gas meter.
|
||||
fn gas_meter(&mut self) -> &mut GasMeter<Self::T>;
|
||||
|
||||
/// Append a string to the debug buffer.
|
||||
///
|
||||
/// It is added as-is without any additional new line.
|
||||
///
|
||||
/// This is a no-op if debug message recording is disabled which is always the case
|
||||
/// when the code is executing on-chain.
|
||||
///
|
||||
/// Returns `true` if debug message recording is enabled. Otherwise `false` is returned.
|
||||
fn append_debug_buffer(&mut self, msg: &str) -> bool;
|
||||
}
|
||||
|
||||
/// Describes the different functions that can be exported by an [`Executable`].
|
||||
@@ -434,6 +444,11 @@ pub struct Stack<'a, T: Config, E> {
|
||||
frames: SmallVec<T::CallStack>,
|
||||
/// Statically guarantee that each call stack has at least one frame.
|
||||
first_frame: Frame<T>,
|
||||
/// A text buffer used to output human readable information.
|
||||
///
|
||||
/// All the bytes added to this field should be valid UTF-8. The buffer has no defined
|
||||
/// structure and is intended to be shown to users as-is for debugging purposes.
|
||||
debug_message: Option<&'a mut Vec<u8>>,
|
||||
/// No executable is held by the struct but influences its behaviour.
|
||||
_phantom: PhantomData<E>,
|
||||
}
|
||||
@@ -442,6 +457,11 @@ pub struct Stack<'a, T: Config, E> {
|
||||
///
|
||||
/// For each nested contract call or instantiate one frame is created. It holds specific
|
||||
/// information for the said call and caches the in-storage `ContractInfo` data structure.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This is an internal data structure. It is exposed to the public for the sole reason
|
||||
/// of specifying [`Config::CallStack`].
|
||||
pub struct Frame<T: Config> {
|
||||
/// The account id of the executing contract.
|
||||
account_id: T::AccountId,
|
||||
@@ -574,6 +594,11 @@ where
|
||||
{
|
||||
/// Create an run a new call stack by calling into `dest`.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// `debug_message` should only ever be set to `Some` when executing as an RPC because
|
||||
/// it adds allocations and could be abused to drive the runtime into an OOM panic.
|
||||
///
|
||||
/// # Return Value
|
||||
///
|
||||
/// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)>
|
||||
@@ -584,6 +609,7 @@ where
|
||||
schedule: &'a Schedule<T>,
|
||||
value: BalanceOf<T>,
|
||||
input_data: Vec<u8>,
|
||||
debug_message: Option<&'a mut Vec<u8>>,
|
||||
) -> Result<(ExecReturnValue, u32), (ExecError, u32)> {
|
||||
let (mut stack, executable) = Self::new(
|
||||
FrameArgs::Call{dest, cached_info: None},
|
||||
@@ -591,12 +617,18 @@ where
|
||||
gas_meter,
|
||||
schedule,
|
||||
value,
|
||||
debug_message,
|
||||
)?;
|
||||
stack.run(executable, input_data)
|
||||
}
|
||||
|
||||
/// Create and run a new call stack by instantiating a new contract.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// `debug_message` should only ever be set to `Some` when executing as an RPC because
|
||||
/// it adds allocations and could be abused to drive the runtime into an OOM panic.
|
||||
///
|
||||
/// # Return Value
|
||||
///
|
||||
/// Result<(NewContractAccountId, ExecReturnValue), ExecError)>
|
||||
@@ -608,6 +640,7 @@ where
|
||||
value: BalanceOf<T>,
|
||||
input_data: Vec<u8>,
|
||||
salt: &[u8],
|
||||
debug_message: Option<&'a mut Vec<u8>>,
|
||||
) -> Result<(T::AccountId, ExecReturnValue), ExecError> {
|
||||
let (mut stack, executable) = Self::new(
|
||||
FrameArgs::Instantiate {
|
||||
@@ -620,6 +653,7 @@ where
|
||||
gas_meter,
|
||||
schedule,
|
||||
value,
|
||||
debug_message,
|
||||
).map_err(|(e, _code_len)| e)?;
|
||||
let account_id = stack.top_frame().account_id.clone();
|
||||
stack.run(executable, input_data)
|
||||
@@ -634,6 +668,7 @@ where
|
||||
gas_meter: &'a mut GasMeter<T>,
|
||||
schedule: &'a Schedule<T>,
|
||||
value: BalanceOf<T>,
|
||||
debug_message: Option<&'a mut Vec<u8>>,
|
||||
) -> Result<(Self, E), (ExecError, u32)> {
|
||||
let (first_frame, executable) = Self::new_frame(args, value, gas_meter, 0, &schedule)?;
|
||||
let stack = Self {
|
||||
@@ -645,6 +680,7 @@ where
|
||||
account_counter: None,
|
||||
first_frame,
|
||||
frames: Default::default(),
|
||||
debug_message,
|
||||
_phantom: Default::default(),
|
||||
};
|
||||
|
||||
@@ -841,6 +877,7 @@ where
|
||||
|
||||
// Pop the current frame from the stack and return it in case it needs to interact
|
||||
// with duplicates that might exist on the stack.
|
||||
// A `None` means that we are returning from the `first_frame`.
|
||||
let frame = self.frames.pop();
|
||||
|
||||
if let Some(frame) = frame {
|
||||
@@ -872,6 +909,13 @@ where
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(message) = &self.debug_message {
|
||||
log::debug!(
|
||||
target: "runtime::contracts",
|
||||
"Debug Message: {}",
|
||||
core::str::from_utf8(message).unwrap_or("<Invalid UTF8>"),
|
||||
);
|
||||
}
|
||||
// Write back to the root gas meter.
|
||||
self.gas_meter.absorb_nested(mem::take(&mut self.first_frame.nested_meter));
|
||||
// Only gas counter changes are persisted in case of a failure.
|
||||
@@ -1181,7 +1225,7 @@ where
|
||||
fn block_number(&self) -> T::BlockNumber { self.block_number }
|
||||
|
||||
fn max_value_size(&self) -> u32 {
|
||||
T::MaxValueSize::get()
|
||||
T::Schedule::get().limits.payload_len
|
||||
}
|
||||
|
||||
fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T> {
|
||||
@@ -1199,6 +1243,17 @@ where
|
||||
fn gas_meter(&mut self) -> &mut GasMeter<Self::T> {
|
||||
&mut self.top_frame_mut().nested_meter
|
||||
}
|
||||
|
||||
fn append_debug_buffer(&mut self, msg: &str) -> bool {
|
||||
if let Some(buffer) = &mut self.debug_message {
|
||||
if !msg.is_empty() {
|
||||
buffer.extend(msg.as_bytes());
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deposit_event<T: Config>(
|
||||
@@ -1241,7 +1296,7 @@ mod tests {
|
||||
test_utils::{place_contract, set_balance, get_balance},
|
||||
},
|
||||
exec::ExportedFunction::*,
|
||||
Error, Weight, CurrentSchedule,
|
||||
Error, Weight,
|
||||
};
|
||||
use sp_core::Bytes;
|
||||
use sp_runtime::DispatchError;
|
||||
@@ -1436,12 +1491,12 @@ mod tests {
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
place_contract(&BOB, exec_ch);
|
||||
|
||||
assert_matches!(
|
||||
MockStack::run_call(
|
||||
ALICE, BOB, &mut gas_meter, &schedule, value, vec![],
|
||||
ALICE, BOB, &mut gas_meter, &schedule, value, vec![], None,
|
||||
),
|
||||
Ok(_)
|
||||
);
|
||||
@@ -1487,7 +1542,7 @@ mod tests {
|
||||
);
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
place_contract(&BOB, return_ch);
|
||||
set_balance(&origin, 100);
|
||||
let balance = get_balance(&dest);
|
||||
@@ -1499,6 +1554,7 @@ mod tests {
|
||||
&schedule,
|
||||
55,
|
||||
vec![],
|
||||
None,
|
||||
).unwrap();
|
||||
|
||||
assert!(!output.0.is_success());
|
||||
@@ -1548,7 +1604,7 @@ mod tests {
|
||||
);
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
place_contract(&BOB, return_ch);
|
||||
|
||||
let result = MockStack::run_call(
|
||||
@@ -1558,6 +1614,7 @@ mod tests {
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
);
|
||||
|
||||
let output = result.unwrap();
|
||||
@@ -1578,8 +1635,8 @@ mod tests {
|
||||
);
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
place_contract(&dest, return_ch);
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
place_contract(&BOB, return_ch);
|
||||
|
||||
let result = MockStack::run_call(
|
||||
origin,
|
||||
@@ -1588,6 +1645,7 @@ mod tests {
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
);
|
||||
|
||||
let output = result.unwrap();
|
||||
@@ -1605,7 +1663,7 @@ mod tests {
|
||||
|
||||
// This one tests passing the input data into a contract via call.
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
place_contract(&BOB, input_data_ch);
|
||||
|
||||
let result = MockStack::run_call(
|
||||
@@ -1615,6 +1673,7 @@ mod tests {
|
||||
&schedule,
|
||||
0,
|
||||
vec![1, 2, 3, 4],
|
||||
None,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -1629,7 +1688,7 @@ mod tests {
|
||||
|
||||
// This one tests passing the input data into a contract via instantiate.
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let subsistence = Contracts::<Test>::subsistence_threshold();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
let executable = MockExecutable::from_storage(
|
||||
@@ -1646,6 +1705,7 @@ mod tests {
|
||||
subsistence * 3,
|
||||
vec![1, 2, 3, 4],
|
||||
&[],
|
||||
None,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -1683,7 +1743,7 @@ mod tests {
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
set_balance(&BOB, 1);
|
||||
place_contract(&BOB, recurse_ch);
|
||||
|
||||
@@ -1694,6 +1754,7 @@ mod tests {
|
||||
&schedule,
|
||||
value,
|
||||
vec![],
|
||||
None,
|
||||
);
|
||||
|
||||
assert_matches!(result, Ok(_));
|
||||
@@ -1732,7 +1793,7 @@ mod tests {
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
place_contract(&dest, bob_ch);
|
||||
place_contract(&CHARLIE, charlie_ch);
|
||||
|
||||
@@ -1743,6 +1804,7 @@ mod tests {
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
);
|
||||
|
||||
assert_matches!(result, Ok(_));
|
||||
@@ -1771,7 +1833,7 @@ mod tests {
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
place_contract(&BOB, bob_ch);
|
||||
place_contract(&CHARLIE, charlie_ch);
|
||||
|
||||
@@ -1782,6 +1844,7 @@ mod tests {
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
);
|
||||
|
||||
assert_matches!(result, Ok(_));
|
||||
@@ -1793,7 +1856,7 @@ mod tests {
|
||||
let dummy_ch = MockLoader::insert(Constructor, |_, _| exec_success());
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
let executable = MockExecutable::from_storage(
|
||||
dummy_ch, &schedule, &mut gas_meter
|
||||
@@ -1808,6 +1871,7 @@ mod tests {
|
||||
0, // <- zero endowment
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
),
|
||||
Err(_)
|
||||
);
|
||||
@@ -1822,7 +1886,7 @@ mod tests {
|
||||
);
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
let executable = MockExecutable::from_storage(
|
||||
dummy_ch, &schedule, &mut gas_meter
|
||||
@@ -1838,6 +1902,7 @@ mod tests {
|
||||
100,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
),
|
||||
Ok((address, ref output)) if output.data == Bytes(vec![80, 65, 83, 83]) => address
|
||||
);
|
||||
@@ -1859,7 +1924,7 @@ mod tests {
|
||||
);
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
let executable = MockExecutable::from_storage(
|
||||
dummy_ch, &schedule, &mut gas_meter
|
||||
@@ -1875,6 +1940,7 @@ mod tests {
|
||||
100,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
),
|
||||
Ok((address, ref output)) if output.data == Bytes(vec![70, 65, 73, 76]) => address
|
||||
);
|
||||
@@ -1908,13 +1974,13 @@ mod tests {
|
||||
});
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
set_balance(&ALICE, Contracts::<Test>::subsistence_threshold() * 100);
|
||||
place_contract(&BOB, instantiator_ch);
|
||||
|
||||
assert_matches!(
|
||||
MockStack::run_call(
|
||||
ALICE, BOB, &mut GasMeter::<Test>::new(GAS_LIMIT), &schedule, 20, vec![],
|
||||
ALICE, BOB, &mut GasMeter::<Test>::new(GAS_LIMIT), &schedule, 20, vec![], None,
|
||||
),
|
||||
Ok(_)
|
||||
);
|
||||
@@ -1958,14 +2024,14 @@ mod tests {
|
||||
});
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
set_balance(&ALICE, 1000);
|
||||
set_balance(&BOB, 100);
|
||||
place_contract(&BOB, instantiator_ch);
|
||||
|
||||
assert_matches!(
|
||||
MockStack::run_call(
|
||||
ALICE, BOB, &mut GasMeter::<Test>::new(GAS_LIMIT), &schedule, 20, vec![],
|
||||
ALICE, BOB, &mut GasMeter::<Test>::new(GAS_LIMIT), &schedule, 20, vec![], None,
|
||||
),
|
||||
Ok(_)
|
||||
);
|
||||
@@ -1987,7 +2053,7 @@ mod tests {
|
||||
.existential_deposit(15)
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
let executable = MockExecutable::from_storage(
|
||||
terminate_ch, &schedule, &mut gas_meter
|
||||
@@ -2003,6 +2069,7 @@ mod tests {
|
||||
100,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
),
|
||||
Err(Error::<Test>::TerminatedInConstructor.into())
|
||||
);
|
||||
@@ -2027,7 +2094,7 @@ mod tests {
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let subsistence = Contracts::<Test>::subsistence_threshold();
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
let executable = MockExecutable::from_storage(
|
||||
rent_allowance_ch, &schedule, &mut gas_meter
|
||||
@@ -2042,6 +2109,7 @@ mod tests {
|
||||
subsistence * 5,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -2060,7 +2128,7 @@ mod tests {
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let subsistence = Contracts::<Test>::subsistence_threshold();
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, subsistence * 10);
|
||||
place_contract(&BOB, code_hash);
|
||||
@@ -2071,6 +2139,7 @@ mod tests {
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
).unwrap();
|
||||
});
|
||||
}
|
||||
@@ -2109,7 +2178,7 @@ mod tests {
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let subsistence = Contracts::<Test>::subsistence_threshold();
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, subsistence * 100);
|
||||
place_contract(&BOB, code_hash);
|
||||
@@ -2120,6 +2189,7 @@ mod tests {
|
||||
&schedule,
|
||||
subsistence * 50,
|
||||
vec![],
|
||||
None,
|
||||
).unwrap();
|
||||
});
|
||||
}
|
||||
@@ -2156,7 +2226,7 @@ mod tests {
|
||||
|
||||
// This one tests passing the input data into a contract via call.
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
place_contract(&BOB, code_bob);
|
||||
place_contract(&CHARLIE, code_charlie);
|
||||
|
||||
@@ -2167,6 +2237,7 @@ mod tests {
|
||||
&schedule,
|
||||
0,
|
||||
vec![0],
|
||||
None,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -2174,10 +2245,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn recursive_call_during_constructor_fails() {
|
||||
let code = MockLoader::insert(Constructor, |ctx, executable| {
|
||||
let my_hash = <Contracts<Test>>::contract_address(&ALICE, &executable.code_hash, &[]);
|
||||
let code = MockLoader::insert(Constructor, |ctx, _| {
|
||||
assert_matches!(
|
||||
ctx.ext.call(0, my_hash, 0, vec![]),
|
||||
ctx.ext.call(0, ctx.ext.address().clone(), 0, vec![]),
|
||||
Err((ExecError{error, ..}, _)) if error == <Error<Test>>::NotCallable.into()
|
||||
);
|
||||
exec_success()
|
||||
@@ -2185,7 +2255,7 @@ mod tests {
|
||||
|
||||
// This one tests passing the input data into a contract via instantiate.
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <CurrentSchedule<Test>>::get();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let subsistence = Contracts::<Test>::subsistence_threshold();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
let executable = MockExecutable::from_storage(
|
||||
@@ -2202,8 +2272,70 @@ mod tests {
|
||||
subsistence * 3,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn printing_works() {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
ctx.ext.append_debug_buffer("This is a test");
|
||||
ctx.ext.append_debug_buffer("More text");
|
||||
exec_success()
|
||||
});
|
||||
|
||||
let mut debug_buffer = Vec::new();
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let subsistence = Contracts::<Test>::subsistence_threshold();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, subsistence * 10);
|
||||
place_contract(&BOB, code_hash);
|
||||
MockStack::run_call(
|
||||
ALICE,
|
||||
BOB,
|
||||
&mut gas_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
Some(&mut debug_buffer),
|
||||
).unwrap();
|
||||
});
|
||||
|
||||
assert_eq!(&String::from_utf8(debug_buffer).unwrap(), "This is a testMore text");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn printing_works_on_fail() {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
ctx.ext.append_debug_buffer("This is a test");
|
||||
ctx.ext.append_debug_buffer("More text");
|
||||
exec_trapped()
|
||||
});
|
||||
|
||||
let mut debug_buffer = Vec::new();
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let subsistence = Contracts::<Test>::subsistence_threshold();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, subsistence * 10);
|
||||
place_contract(&BOB, code_hash);
|
||||
let result = MockStack::run_call(
|
||||
ALICE,
|
||||
BOB,
|
||||
&mut gas_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
Some(&mut debug_buffer),
|
||||
);
|
||||
assert!(result.is_err());
|
||||
});
|
||||
|
||||
assert_eq!(&String::from_utf8(debug_buffer).unwrap(), "This is a testMore text");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user