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

Updated WASM Runtime & new interpreter (wasmi) #7796

Merged
merged 1 commit into from
Feb 5, 2018
Merged

Updated WASM Runtime & new interpreter (wasmi) #7796

merged 1 commit into from
Feb 5, 2018

Conversation

NikVolf
Copy link
Contributor

@NikVolf NikVolf commented Feb 2, 2018

cc @pepyakin

  • mem* removed from the runtime, we'll add it back if optimization needed
  • wasmi replaces deprecated parity-wasm interpreter
  • wasm32-unknown-unknown import/export name conventions
  • dropped emscripten runtime glue completely (STACKTOP, llvmtrap, memory base, etc..)
  • added wasm opcodes scaling factor of 3/8

@NikVolf NikVolf added A0-pleasereview 🤓 Pull request needs code review. M4-core ⛓ Core client code / Rust. A3-inprogress ⏳ Pull request is in progress. No review needed at this stage. and removed A0-pleasereview 🤓 Pull request needs code review. labels Feb 2, 2018
@@ -516,128 +519,10 @@ fn keccak() {
};

assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
assert_eq!(gas_left, U256::from(81_067));
assert_eq!(gas_left, U256::from(70_217));
}

// memcmp test.
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you delete this line too?

}

pub fn call(&mut self, context: InterpreterCallerContext)
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
/// Read from the storage to wasm memory
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this should be the other way around: from wasm memory to the storage?


if params.gas > ::std::u64::MAX.into() {
return Err(vm::Error::Wasm("Wasm interpreter cannot run contracts with gas >= 2^64".to_owned()));
}

let initial_memory = instantiation_resolover.memory_size().map_err(Error)?
.saturating_sub(MEMORY_STIPEND);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is quite obscure IMO, could you please add comment clarifying why this is here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I moved to the schedule

&self.result
}

pub fn dissolve(self) -> Vec<u8> {
Copy link
Contributor

Choose a reason for hiding this comment

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

How about into_result?

@NikVolf NikVolf force-pushed the wasmi branch 3 times, most recently from 25afff3 to f85433b Compare February 4, 2018 17:02
@NikVolf
Copy link
Contributor Author

NikVolf commented Feb 4, 2018

@pepyakin addressed

@NikVolf NikVolf added A0-pleasereview 🤓 Pull request needs code review. and removed A3-inprogress ⏳ Pull request is in progress. No review needed at this stage. labels Feb 4, 2018
@5chdn 5chdn added this to the 1.10 milestone Feb 5, 2018
@NikVolf NikVolf force-pushed the wasmi branch 3 times, most recently from 7db1f31 to 1332adf Compare February 5, 2018 16:08
pub fn with_limit(max_memory: u32) -> ImportResolver {
ImportResolver {
max_memory: max_memory,
.. Default::default()
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this supposed to be memory (0, 0)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I see.
Maybe it would be better to explicitly initialize memory
like RefCell::new(None) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed!

pub fn memory_ref(&self) -> Result<MemoryRef, Error> {
{
let mut mem_ref = self.memory.borrow_mut();
if mem_ref.is_none() { *mem_ref = Some(MemoryInstance::alloc(0, Some(0))?); }
Copy link
Contributor

Choose a reason for hiding this comment

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

This invocation actually can't return error since params (0, Some(0)) are perfectly valid

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But i don't want to depend on this invariant from other lib

Copy link
Contributor

Choose a reason for hiding this comment

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

But otherwise this code embeds this invariant into the consensus

}
}

impl wasmi::ModuleImportResolver for ImportResolver {
// todo: check against `_signature` ?
Copy link
Contributor

Choose a reason for hiding this comment

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

stray TODO

IMO we should check signatures early and don't rely that execution engine will check them for us.


impl ImportResolver {
/// New import resolver with specifed maximum amount of inital memory.
pub fn with_limit(max_memory: u32) -> ImportResolver {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it is not clear that max_memory is denoted in pages. Maybe it would be better if we leave a comments on this? Or maybe change the name to something like max_memory_pages

) -> Result<MemoryRef, Error> {
if field_name == "memory" {
if descriptor.initial() >= self.max_memory ||
(descriptor.maximum().map_or(false, |m| m < descriptor.initial() || m > self.max_memory))
Copy link
Contributor

Choose a reason for hiding this comment

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

This is an interesting check.

If I understand the intent correctly, it checks whether initial or maximum number of memory pages requested by the module is greater than some limit. In case if maximum isn't provided then this check is passed and runtime proceeds to execution.

If that's correct, then I don't see the point. What stops the contract writer to not set maximum limit on memory and then allocate amount of memory larger than the limit (don't we have the control on grow_memory op, do we?).

And as I remember, don't we agreed that we don't want to restrict the upper memory limit by any means except the gas price?

@NikVolf NikVolf force-pushed the wasmi branch 2 times, most recently from 5446ec8 to b33fca5 Compare February 5, 2018 16:37
/// Internal ids all functions runtime supports. This is just a glue for wasmi interpreter
/// that lacks high-level api and later will be factored out
pub mod ids {
pub const STORAGE_WRITE_FUNC: usize = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see the point of this 10-step numbering.
Also, maybe we can use some macro which will generate C-like enum, so we don't have to number this constants by hand?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's implementation detail, will refactored once more high-level api for wasmi is available

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, I think I'm fine with it.

} else {
Ok(())
}
}

pub fn overflow_charge<F>(&mut self, f: F) -> Result<(), InterpreterError>
/// Adjusted charge applies wasm divisor coeff as
Copy link
Contributor

Choose a reason for hiding this comment

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

Im not sure what you meant here...

@NikVolf NikVolf force-pushed the wasmi branch 3 times, most recently from 9fac2ff to 4ae0130 Compare February 5, 2018 16:54
@NikVolf NikVolf removed this from the 1.10 milestone Feb 5, 2018
}

/// Return. Syscall takes 2 arguments - pointer in sandboxed memory where result is and
/// the lendth of the result.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: lendth → length

@NikVolf NikVolf force-pushed the wasmi branch 2 times, most recently from e9bdba7 to 9716018 Compare February 5, 2018 17:03
let result_alloc_len = context.value_stack.pop_as::<i32>()? as u32;
trace!(target: "wasm", " result_len: {:?}", result_alloc_len);
let vofs = if use_val { 1 } else { 0 };
let val = if use_val { Some(self.u256_at(args.nth(2)?)?) } else { None };
Copy link
Contributor

Choose a reason for hiding this comment

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

I think such sorta dynamic signatures might lead to a disaster.
Can we fix this somehow? For example, change pwasm-std in a such way that we always pass some dummy val parameter?
I think even duplicating parameter decoding in methods *call below would be a better solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It won't lead to disaster if there is test that shows that all arguments are mapped correctly, which is the case here

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we do this multiplexing on the pwasm-std side? This way we'll get rid of all this dcall/scall and etc exports.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so, these are mostly different operations, and might be handled completely differently lately, so it might be good idea to differentiate them at link time

also, EVM has different opcodes for those, so it's good to have 1-1 mapping opcode<->wasm external

let code_len: u32 = args.nth(2)?;
trace!(target: "wasm", " code_len: {:?}", code_len);
let result_ptr: u32 = args.nth(3)?;
trace!(target: "wasm", "result_ptr: {:?}", result_ptr);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this code will more legible if we won't interleave argument decoding code with displaying it, as we do in do_call.
At least, I'm wondering, should we synchronize them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

why?

@NikVolf NikVolf force-pushed the wasmi branch 2 times, most recently from 448c914 to 249327e Compare February 5, 2018 17:22
runtime.write_descriptor(
if data_position < code.len() { &code[data_position..] } else { &[] }
).map_err(Error)?
// We count all memory except free (MEMORY_STIPEND)
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the MEMORY_STIPEND?

@NikVolf
Copy link
Contributor Author

NikVolf commented Feb 5, 2018

@pepyakin all addressed

@pepyakin pepyakin added A8-looksgood 🦄 Pull request is reviewed well. and removed A0-pleasereview 🤓 Pull request needs code review. labels Feb 5, 2018
@5chdn 5chdn added this to the 1.10 milestone Feb 5, 2018
@5chdn 5chdn merged commit fb4582a into master Feb 5, 2018
@5chdn 5chdn deleted the wasmi branch February 5, 2018 19:59
tomusdrw pushed a commit that referenced this pull request Feb 14, 2018
5chdn pushed a commit that referenced this pull request Feb 14, 2018
* update back-references more aggressively after answering from cache (#7578)

* Add new EF ropstens nodes. (#7824)

* Add new EF ropstens nodes.

* Fix tests

* Add a timeout for light client sync requests (#7848)

* Add a timeout for light client sync requests

* Adjusting timeout to number of headers

* Flush keyfiles. Resolves #7632 (#7868)

* Fix wallet import (#7873)

* rpc: generate new account id for imported wallets

* ethstore: handle duplicate wallet filenames

* ethstore: simplify deduplication of wallet file names

* ethstore: do not dedup wallet filenames on update

* ethstore: fix minor grumbles

* [WASM] mem_cmp added to the Wasm runtime (#7539)

* mem_cmp added to the Wasm runtime

* schedule.wasm.mem_copy to schedule.wasm.mem_cmp for mem_cmp

* [Wasm] memcmp fix and test added (#7590)

* [Wasm] memcmp fix and test added

* [Wasm] use reqrep_test! macro for memcmp test

* wasmi interpreter (#7796)

* adjust storage update evm-style (#7812)

* disable internal memory (#7842)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A8-looksgood 🦄 Pull request is reviewed well. M4-core ⛓ Core client code / Rust.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants