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

Introduce ext_println to contract runtime #2239

Merged
merged 6 commits into from
Apr 11, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 20 additions & 13 deletions node/cli/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ pub fn testnet_genesis(
initial_authorities: Vec<(AccountId, AccountId, AuthorityId)>,
root_key: AccountId,
endowed_accounts: Option<Vec<AccountId>>,
enable_println: bool,
) -> GenesisConfig {
let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(|| {
vec![
Expand All @@ -237,6 +238,22 @@ pub fn testnet_genesis(
const STASH: 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 {
consensus: Some(ConsensusConfig {
code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(),
Expand Down Expand Up @@ -308,19 +325,7 @@ pub fn testnet_genesis(
spend_period: 12 * 60 * 24,
burn: Permill::from_percent(50),
}),
contract: Some(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(),
}),
contract: Some(contract_config),
sudo: Some(SudoConfig {
key: root_key,
}),
Expand All @@ -337,6 +342,7 @@ fn development_config_genesis() -> GenesisConfig {
],
get_account_id_from_seed("Alice"),
None,
true,
)
}

Expand All @@ -353,6 +359,7 @@ fn local_testnet_genesis() -> GenesisConfig {
],
get_account_id_from_seed("Alice"),
None,
false,
)
}

Expand Down
2 changes: 1 addition & 1 deletion node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node"),
impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10,
spec_version: 58,
spec_version: 59,
impl_version: 59,
apis: RUNTIME_API_VERSIONS,
};
Expand Down
5 changes: 5 additions & 0 deletions srml/contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,10 @@ pub struct Schedule<Gas> {
/// What is the maximal memory pages amount is allowed to have for
/// a contract.
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> {
Expand All @@ -543,6 +547,7 @@ impl<Gas: As<u64>> Default for Schedule<Gas> {
sandbox_data_write_cost: Gas::sa(1),
max_stack_height: 64 * 1024,
max_memory_pages: 16,
enable_println: false,
}
}
}
38 changes: 38 additions & 0 deletions srml/contract/src/wasm/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ impl<'a, Gas: 'a + As<u32> + Clone> ContractModule<'a, Gas> {
.get(*type_idx as usize)
.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.
if import.field().as_bytes() == b"gas"
|| !C::can_satisfy(import.field().as_bytes(), func_ty)
Expand Down Expand Up @@ -347,6 +353,8 @@ mod tests {
gas(_ctx, _amount: u32) => { unreachable!(); },

nop(_ctx, _unused: u64) => { unreachable!(); },

ext_println(_ctx, _ptr: u32, _len: u32) => { unreachable!(); },
);

macro_rules! prepare_test {
Expand Down Expand Up @@ -572,6 +580,36 @@ mod tests {
"#,
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 {
Expand Down
11 changes: 11 additions & 0 deletions srml/contract/src/wasm/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,4 +628,15 @@ define_env!(Env, <E: Ext>,

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);
bkchr marked this conversation as resolved.
Show resolved Hide resolved
}
Ok(())
},
);