mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-22 06:45:41 +00:00
Introduce ext_println to contract runtime (#2239)
* Implement `ext_println` in contract runtime * Only allow contracts to import `ext_println` on dev chains * Configure dev chain to allow contracts with `ext_println` * Increment spec version * Docs * Rename config to the more specific enable_println
This commit is contained in:
committed by
Sergei Pepyakin
parent
18df051947
commit
1e0c1d8850
@@ -216,6 +216,7 @@ pub fn testnet_genesis(
|
|||||||
initial_authorities: Vec<(AccountId, AccountId, AuthorityId)>,
|
initial_authorities: Vec<(AccountId, AccountId, AuthorityId)>,
|
||||||
root_key: AccountId,
|
root_key: AccountId,
|
||||||
endowed_accounts: Option<Vec<AccountId>>,
|
endowed_accounts: Option<Vec<AccountId>>,
|
||||||
|
enable_println: bool,
|
||||||
) -> GenesisConfig {
|
) -> GenesisConfig {
|
||||||
let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(|| {
|
let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(|| {
|
||||||
vec![
|
vec![
|
||||||
@@ -237,6 +238,22 @@ pub fn testnet_genesis(
|
|||||||
const STASH: u128 = 1 << 20;
|
const STASH: u128 = 1 << 20;
|
||||||
const ENDOWMENT: u128 = 1 << 20;
|
const ENDOWMENT: u128 = 1 << 20;
|
||||||
|
|
||||||
|
let mut contract_config = ContractConfig {
|
||||||
|
transaction_base_fee: 1,
|
||||||
|
transaction_byte_fee: 0,
|
||||||
|
transfer_fee: 0,
|
||||||
|
creation_fee: 0,
|
||||||
|
contract_fee: 21,
|
||||||
|
call_base_fee: 135,
|
||||||
|
create_base_fee: 175,
|
||||||
|
gas_price: 1,
|
||||||
|
max_depth: 1024,
|
||||||
|
block_gas_limit: 10_000_000,
|
||||||
|
current_schedule: Default::default(),
|
||||||
|
};
|
||||||
|
// this should only be enabled on development chains
|
||||||
|
contract_config.current_schedule.enable_println = enable_println;
|
||||||
|
|
||||||
GenesisConfig {
|
GenesisConfig {
|
||||||
consensus: Some(ConsensusConfig {
|
consensus: Some(ConsensusConfig {
|
||||||
code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(),
|
code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(),
|
||||||
@@ -308,19 +325,7 @@ pub fn testnet_genesis(
|
|||||||
spend_period: 12 * 60 * 24,
|
spend_period: 12 * 60 * 24,
|
||||||
burn: Permill::from_percent(50),
|
burn: Permill::from_percent(50),
|
||||||
}),
|
}),
|
||||||
contract: Some(ContractConfig {
|
contract: Some(contract_config),
|
||||||
transaction_base_fee: 1,
|
|
||||||
transaction_byte_fee: 0,
|
|
||||||
transfer_fee: 0,
|
|
||||||
creation_fee: 0,
|
|
||||||
contract_fee: 21,
|
|
||||||
call_base_fee: 135,
|
|
||||||
create_base_fee: 175,
|
|
||||||
gas_price: 1,
|
|
||||||
max_depth: 1024,
|
|
||||||
block_gas_limit: 10_000_000,
|
|
||||||
current_schedule: Default::default(),
|
|
||||||
}),
|
|
||||||
sudo: Some(SudoConfig {
|
sudo: Some(SudoConfig {
|
||||||
key: root_key,
|
key: root_key,
|
||||||
}),
|
}),
|
||||||
@@ -337,6 +342,7 @@ fn development_config_genesis() -> GenesisConfig {
|
|||||||
],
|
],
|
||||||
get_account_id_from_seed("Alice"),
|
get_account_id_from_seed("Alice"),
|
||||||
None,
|
None,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,6 +359,7 @@ fn local_testnet_genesis() -> GenesisConfig {
|
|||||||
],
|
],
|
||||||
get_account_id_from_seed("Alice"),
|
get_account_id_from_seed("Alice"),
|
||||||
None,
|
None,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
spec_name: create_runtime_str!("node"),
|
spec_name: create_runtime_str!("node"),
|
||||||
impl_name: create_runtime_str!("substrate-node"),
|
impl_name: create_runtime_str!("substrate-node"),
|
||||||
authoring_version: 10,
|
authoring_version: 10,
|
||||||
spec_version: 58,
|
spec_version: 59,
|
||||||
impl_version: 59,
|
impl_version: 59,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -527,6 +527,10 @@ pub struct Schedule<Gas> {
|
|||||||
/// What is the maximal memory pages amount is allowed to have for
|
/// What is the maximal memory pages amount is allowed to have for
|
||||||
/// a contract.
|
/// a contract.
|
||||||
pub max_memory_pages: u32,
|
pub max_memory_pages: u32,
|
||||||
|
|
||||||
|
/// Whether the `ext_println` function is allowed to be used contracts.
|
||||||
|
/// MUST only be enabled for `dev` chains, NOT for production chains
|
||||||
|
pub enable_println: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Gas: As<u64>> Default for Schedule<Gas> {
|
impl<Gas: As<u64>> Default for Schedule<Gas> {
|
||||||
@@ -543,6 +547,7 @@ impl<Gas: As<u64>> Default for Schedule<Gas> {
|
|||||||
sandbox_data_write_cost: Gas::sa(1),
|
sandbox_data_write_cost: Gas::sa(1),
|
||||||
max_stack_height: 64 * 1024,
|
max_stack_height: 64 * 1024,
|
||||||
max_memory_pages: 16,
|
max_memory_pages: 16,
|
||||||
|
enable_println: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,6 +239,12 @@ impl<'a, Gas: 'a + As<u32> + Clone> ContractModule<'a, Gas> {
|
|||||||
.get(*type_idx as usize)
|
.get(*type_idx as usize)
|
||||||
.ok_or_else(|| "validation: import entry points to a non-existent type")?;
|
.ok_or_else(|| "validation: import entry points to a non-existent type")?;
|
||||||
|
|
||||||
|
// We disallow importing `ext_println` unless debug features are enabled,
|
||||||
|
// which should only be allowed on a dev chain
|
||||||
|
if !self.schedule.enable_println && import.field().as_bytes() == b"ext_println" {
|
||||||
|
return Err("module imports `ext_println` but debug features disabled");
|
||||||
|
}
|
||||||
|
|
||||||
// We disallow importing `gas` function here since it is treated as implementation detail.
|
// We disallow importing `gas` function here since it is treated as implementation detail.
|
||||||
if import.field().as_bytes() == b"gas"
|
if import.field().as_bytes() == b"gas"
|
||||||
|| !C::can_satisfy(import.field().as_bytes(), func_ty)
|
|| !C::can_satisfy(import.field().as_bytes(), func_ty)
|
||||||
@@ -347,6 +353,8 @@ mod tests {
|
|||||||
gas(_ctx, _amount: u32) => { unreachable!(); },
|
gas(_ctx, _amount: u32) => { unreachable!(); },
|
||||||
|
|
||||||
nop(_ctx, _unused: u64) => { unreachable!(); },
|
nop(_ctx, _unused: u64) => { unreachable!(); },
|
||||||
|
|
||||||
|
ext_println(_ctx, _ptr: u32, _len: u32) => { unreachable!(); },
|
||||||
);
|
);
|
||||||
|
|
||||||
macro_rules! prepare_test {
|
macro_rules! prepare_test {
|
||||||
@@ -572,6 +580,36 @@ mod tests {
|
|||||||
"#,
|
"#,
|
||||||
Err("module imports a non-existent function")
|
Err("module imports a non-existent function")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
prepare_test!(ext_println_debug_disabled,
|
||||||
|
r#"
|
||||||
|
(module
|
||||||
|
(import "env" "ext_println" (func $ext_println (param i32 i32)))
|
||||||
|
|
||||||
|
(func (export "call"))
|
||||||
|
(func (export "deploy"))
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
Err("module imports `ext_println` but debug features disabled")
|
||||||
|
);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ext_println_debug_enabled() {
|
||||||
|
let wasm = wabt::Wat2Wasm::new().validate(false).convert(
|
||||||
|
r#"
|
||||||
|
(module
|
||||||
|
(import "env" "ext_println" (func $ext_println (param i32 i32)))
|
||||||
|
|
||||||
|
(func (export "call"))
|
||||||
|
(func (export "deploy"))
|
||||||
|
)
|
||||||
|
"#
|
||||||
|
).unwrap();
|
||||||
|
let mut schedule = Schedule::<u64>::default();
|
||||||
|
schedule.enable_println = true;
|
||||||
|
let r = prepare_contract::<Test, TestEnv>(wasm.as_ref(), &schedule);
|
||||||
|
assert_matches!(r, Ok(_));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod entrypoints {
|
mod entrypoints {
|
||||||
|
|||||||
@@ -628,4 +628,15 @@ define_env!(Env, <E: Ext>,
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Prints utf8 encoded string from the data buffer.
|
||||||
|
// Only available on `--dev` chains.
|
||||||
|
// This function may be removed at any time, superseded by a more general contract debugging feature.
|
||||||
|
ext_println(ctx, str_ptr: u32, str_len: u32) => {
|
||||||
|
let data = read_sandbox_memory(ctx, str_ptr, str_len)?;
|
||||||
|
if let Ok(utf8) = core::str::from_utf8(&data) {
|
||||||
|
runtime_io::print(utf8);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user