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

Implement runtime version checks in set_code #4548

Merged
merged 17 commits into from
Jan 16, 2020

Conversation

bkchr
Copy link
Member

@bkchr bkchr commented Jan 6, 2020

Check that the new runtime code given to set_code fullfills some
requirements:

  • spec_name matches
  • spec_version does not decreases
  • impl_version does not decreases
  • Either spec_version or impl_version increases

Check that the new runtime code given to `set_code` fullfills some
requirements:

- `spec_name` matches
- `spec_version` does not decreases
- `impl_version` does not decreases
- Either `spec_version` and `impl_version` increase
@bkchr bkchr added the A3-in_progress Pull request is in progress. No review needed at this stage. label Jan 6, 2020
@bkchr bkchr requested a review from gavofyork January 6, 2020 19:56
@gavofyork
Copy link
Member

looks like a promising direction.

@bkchr bkchr marked this pull request as ready for review January 13, 2020 11:53
@bkchr bkchr added A0-please_review Pull request needs code review. and removed A3-in_progress Pull request is in progress. No review needed at this stage. labels Jan 13, 2020
Block: BlockT,
{
type Type = Block;
}

impl<B, E, Block, RA> Client<B, E, Block, RA> where
B: backend::Backend<Block>,
E: CallExecutor<Block>,
E: CallExecutor<Block> + 'static,
Copy link
Contributor

Choose a reason for hiding this comment

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

Shall we just require on CallExecutor trait that it's 'static? This repetition is going to be pretty cumbersome.

///
/// Returns the SCALE encoded runtime version and `None` if the call failed.
fn runtime_version(&mut self, wasm: &[u8]) -> Option<Vec<u8>> {
// Create some dummy externalities, `Core_version` should not write data anyway.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we just error out if it does? Just to make sure that even if set_code fails due to checks there are no side-effects of that.

Copy link
Member Author

Choose a reason for hiding this comment

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

What kind of side effects? Even if the call would write something, it would not leak into the Externalities of the actual block. If that was your question.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, that's what I meant, I wanted to be sure that the two contexts do not share anything.

println!("{} {}", module_name, field_name);
let lol = ExternVal::HostFunc(HostFuncIndex(100));
let externval = self.map.get(&key).unwrap_or_else(|| {
// wasmi::Error::Instantiation(format!("Export {}:{} not found", module_name, field_name))
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 going on here 🗡️

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I had forgot some debugging stuff 😅 Good that you found it!

@@ -262,10 +266,9 @@ impl<T> Instance<T> {
env_def_builder: &EnvironmentDefinitionBuilder<T>,
state: &mut T,
) -> Result<Instance<T>, Error> {
let module = Module::from_buffer(code).map_err(|_| Error::Module)?;
let module = Module::from_buffer(code).map_err(|e| { println!("{:?}", e); Error::Module})?;
Copy link
Contributor

Choose a reason for hiding this comment

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

A bunch of stray printlns in this file.

) -> Self {
extensions.register(CallInWasmExt::new(exec.clone()));
Copy link
Contributor

Choose a reason for hiding this comment

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

So it's now available to every runtime call I guess, what are the consequences here? Besides using it being super slow, as I guess a new wasm env has to be initiated.

Copy link
Member Author

Choose a reason for hiding this comment

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

Why super slow? The wasm blob needs to be initialized when we want to call some function in it, but there is nothing we can optimize (as we don't know the blob in front of).

We need the extension while building/executing a block. But there is also no direct method that you can call from the runtime, besides the one that only can call Core_version.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, I know there is no other way to call Core_version from a different runtime blob, but afair when talking with Sergei he was saying that initializing wasm runtime (alloc memory, load module, etc) takes quite some time, hence I've mentioned that it's most likely going to be way slower than any other operation or host function we have, so we need to be careful to avoid using it too often.
I was wondering if there are any other (more severe) consequences of exposing this kind of function to the runtime - i.e. if it can be somehow abused.

. But there is also no direct method that you can call from the runtime, besides the one that only can call Core_version.

That's good to know, so it means that it's not easy to shoot yourself in a foot if you are a runtime developer, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah it is probably no easy operation, but better to include less transactions than to stop the network again ;) If something does not work or for whatever reason we need to put a blob in without any checks, I added set_code_without_checks. This will just do it the old way, so we are sure that we can put a blob in :)

Yeah, the runtime developer can not access the CallInRuntimeExt in any other way. It is not exposed to the runtime. The developer can just call misc::runtime_version that uses this stuff internally.

Copy link
Contributor

@tomusdrw tomusdrw Jan 14, 2020

Choose a reason for hiding this comment

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

Okay, that's fair, but I would really add extra docs to make sure it's not being called as it's a possible DoS vector. Imagine if we do that check whenever someone proposes a runtime, then people can craft arbitrary runtimes and do arbitrary operations within Core_version and it wouldn't be priced correctly. So we should only make sure to run in during set_code, not during any preliminary checks (that accepts unreviewed user's input).

function: &str,
call_data: &[u8],
execution_method: WasmExecutionMethod,
ext: &mut E,
ext: &mut dyn Externalities,
Copy link
Member

Choose a reason for hiding this comment

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

all the storage accesses (and there are a lot) go through externalities. does this really have an insubstantial effect on performance?

Copy link
Member Author

Choose a reason for hiding this comment

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

We store the Externalities as trait pointer in the environmental anyway. The compiler can not optimize this anywax.

@bkchr
Copy link
Member Author

bkchr commented Jan 15, 2020

I added some temporary execution time measuring into runtime_version and the host call takes 60ms. Given the time it takes to execute the transaction itself, this sounds okay and reasonable.

@gavofyork gavofyork added this to the 3.0 milestone Jan 15, 2020
@gavofyork
Copy link
Member

will need resolving

@bkchr
Copy link
Member Author

bkchr commented Jan 16, 2020

will need resolving

Done

@gavofyork gavofyork merged commit 879e28a into master Jan 16, 2020
@gavofyork gavofyork deleted the bkchr-set-code-with-checks branch January 16, 2020 12:58
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-please_review Pull request needs code review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants