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

Native executor#47

Merged
gavofyork merged 124 commits intomasterfrom
native-executor
Jan 30, 2018
Merged

Native executor#47
gavofyork merged 124 commits intomasterfrom
native-executor

Conversation

@gavofyork
Copy link
Copy Markdown
Member

@gavofyork gavofyork commented Jan 23, 2018

Based on #42.

Executes the runtime natively, falling back to wasm if the code at compile time is different to that which should be executed.

Still todo:

  • Panic handler to avoid full on meltdown when runtime hits an error.

$crate::vec::Vec::new()
} else {
unsafe {
$crate::vec::Vec::from_raw_parts(input_data, input_len, input_len)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

as I said earlier in the chat, this will take ownership of this allocation and Vec will drop it at the end of the method. And if for some reason this pointer will be deallocated in other way it was deallocated then some bad things might happen.

I think that the best way to do this is to make client code responsible for deallocating input_data pointer (because the client code allocated this pointer in a first place) and use slice instead of a vector.

If this isn't desired for some reason, then I think it would be better to use slice and deallocate this pointer explicitly, preferably with a comment

}
}

const APPROVALS_REQUIRED: &[u8] = b"gov:apr";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

these constants should be at the top of the file

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ok - i put them down below as they're private and i wanted all public API first.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

for readability I usually prefer any constants to be declared before their usage rather than scattered throughout the file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

otherwise it can be hard to tell if they are actually from that file or imported from elsewhere

if code == &native_equivalent[..] {
runtime_std::with_externalities(ext, || match method {
"execute_block" => safe_call(|| runtime::execute_block(&data.0)),
"execute_transaction" => safe_call(|| runtime::execute_transaction(&data.0)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am little worried about this since &mut T isn't UnwindSafe. But this code compiles because we've hidden the mutable reference in the with_externalities global.

Doesn't have to be for this PR, but the entire runtime should eventually change to not use panics unless the program should actually halt.

assert_eq!(
WasmExecutor.call(&mut ext, &test_code[..], "test_ed25519_verify", &CallData(calldata)).unwrap(),
vec![1]
vec![0]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why this set to 0? Is this workaround?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

0 is the legitimately expected result.

Copy link
Copy Markdown
Contributor

@pepyakin pepyakin Jan 29, 2018

Choose a reason for hiding this comment

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

Hm, could you help me to understand this?

  1. I thought this is a positive test, i.e. checks for successful verification.
  2. Looking at test_ed25519_verify it returns casted bool taken from ed25519_verify to u8, so if ed25519_verify returns true then it should return vec![1u8] or vec![0u8] otherwise.
  3. ed25519_verify have no documentation which one of boolean values returns in case of successful result, but I almost certain that true should be returned for successful verification.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

you're right about point 1, but ed25519_verify returns a u32 not a bool, with success being 0 and error conditions (of which there are several types) being non-zero. test_ed25519_verify is just a passthrough with a u8 cast, so we still expect a 0 for success.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hm, but if you follow my link, https://github.com/paritytech/polkadot/blob/1344dadd131629e39109ca7506d9f004da69eef4/wasm-runtime/std/src/lib.rs#L113
‘ed25519_verify’ in fact returbs a ‘bool’ not a u32

it is ‘ext_ed25519_verify’ returns u32

pub fn ed25519_verify(sig: &[u8], msg: &[u8], pubkey: &[u8]) -> bool {
sig.len() != 64 || pubkey.len() != 32 || unsafe {
ext_ed25519_verify(&msg[0], msg.len() as u32, &sig[0], &pubkey[0])
ext_ed25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ptr())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems to me the code above contains an error, and can be rewritten as:

if sig.len()64 {
  return true;
}
if pubkey.len()32 {
  return true;
}
let err_code = unsafe {
  ext_ed25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ptr())
};
err_code == 0

I guess this isn't intended behavior...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch!

} else {
0
}
},
Copy link
Copy Markdown
Contributor

@pepyakin pepyakin Jan 29, 2018

Choose a reason for hiding this comment

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

memcmp should return 0 if sl1 == sl2, i.e. all bytes are equal,
should return a negative value if first different byte in sl1 is less than byte at the same position in sl2 and should return a positive value if this different byte from sl1 is greater than corresponding byte from sl2.

The problem is memcmp::Memcmp for some reason returns bool value, and seems like it returns true if slices are equal. So this implementation returns 1 in case slices are equal and 0 in other cases.

Also, in case if s1 or s2 can't be read, you return zero. This is not strictly a problem, because passing s1 or s2 which are out of bounds is undefined behavior and for such case returning 0 is perfeclty legal.
However, I strongly recommend to trap here, because:

  1. returning some value, especially 0 (meaning that s1 == s2), might lead to serious security problems,
  2. such behavior will be inline with behavior of memcmp implemented within wasm itself.

Here you can find test cases which might help you to test implementation of memcmp extern.

ext_memcpy(dest, src, n)
}

/// memcpy extern
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

typo memcmp extern (or can we just get rid of these comments?)

@arkpar arkpar self-assigned this Jan 29, 2018
@arkpar arkpar removed their assignment Jan 29, 2018
use memcmp::Memcmp;
(&sl1).memcmp(&sl2) as i32
unsafe {
memcmp(sl1.as_ptr() as *const u8 as *const c_void,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can be replaced with safe code:

match sl1.cmp(&sl2) {
    Ordering::Greater => 1,
    Ordering::Less => -1,
    Ordering::Equal => 0,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

https://doc.rust-lang.org/stable/src/core/slice/mod.rs.html#2571

it's specialized to compile down to a memcmp and be inlined.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

oh nice.

@gavofyork gavofyork merged commit 9d4beb3 into master Jan 30, 2018
@gavofyork gavofyork deleted the native-executor branch January 30, 2018 09:58
JoshOrndorff referenced this pull request in moonbeam-foundation/substrate Apr 21, 2021
iStrike7 referenced this pull request in gasp-xyz/substrate Aug 3, 2021
liuchengxu pushed a commit to chainx-org/substrate that referenced this pull request Aug 23, 2021
* Add runtime/pos module

* Add staking module and new substrate
liuchengxu referenced this pull request in autonomys/substrate Jun 3, 2022
Unify the styling of dependencies in Cargo.toml
vivekvpandya pushed a commit to zeitgeistpm/substrate that referenced this pull request Nov 29, 2022
Pass signature as &[u8] to avoid triggering From::from conversion
helin6 pushed a commit to boolnetwork/substrate that referenced this pull request Jul 25, 2023
* Fix the module index used to create a encoded func

Same as Events, modules with no calls should be ignored when calculating
the module index.

* Update substrate
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.

4 participants