-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Finish implementing initial Simulation interface #26
Conversation
eth2/simulation/src/simulation.rs
Outdated
a: args::CreateExecutionEnvironment, | ||
) -> Result<EEIndex> { | ||
// Create EE struct from args | ||
let vl_wasm_code = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the vl_
prefix a convention from the lighthouse repository?
I think I'd prefer to see just wasm_code
, and use the shorthand assignment in the ExecutionEnvironment
initialization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I'll just use wasm_code
.
#[derive(Debug, Snafu)] | ||
pub enum Error { | ||
#[snafu(display("{} exceeds max allowable length", what))] | ||
MaxLengthExceeded { what: String }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is MaxLengthExceeded
always triggered from a ssz_types::Error
?
Either way, I'd add a source
field here, to give more context on the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, currently MaxLengthExceeded
is only triggered from a ssz_types::Error
. However, I could envision it being useful for other types of errors in the future.
Though, unless I'm misuderstanding Snafu, I believe that 1) I can only use context()?;
if I add a source
field (unless I'm calling .context()
on a function returning an Option
), and 2) this error type will ONLY ever be able to be used for ssz_types::Error
if I do that approach, which could be OK but if so I'd want to change the name from MaxLengthExceeded
to something like SszTypeError
or similar.
One last note: my original implementation did use Snafu's canonical .context(...)?;
pattern, along with a source
field. However, ssz_types::Error
doesn't actually implement std::error::Error
, which means that ssz_types::Error
can't be used as a source
error. Obviously, I can update the ssz_types::Error
type to implement std:error::Error
, but I opted not to do this immediately, since I anticipate that ssz_types
will eventually be a crate instead of "owned code" in this repo. That said, prior to pushing this as a crate, I'm sure the ssz_types
authors would make the Error
type compliant with the std::error::Error
trait.
TL;DR: I don't feel too strongly here, as I see it, there are 2 paths forward:
- Leave it as-is, and update in the future if we want the granularity / lower-level visibility into the ssz_types error.
- Change to have this use a
source
field now, which would entail:
- Updating the
ssz_types::Error
field to implement thestd:error:Error
trait - Likely changing the name of this wrapper error from
MaxLengthExceeded
to something likeSszTypeError
, and have the display implementation of the wrapper just show the underlying display implementation of the ssz error (which I would have just added in the first bullet point). This way the error could wrap any of the ssz error types that may come back.
Either way works, and #2 is fairly easy to do. #2 has the advantage of the lower-level visibility, and would make it easier to give more info like what the max length was when it was exceeded. #1 is obviously already in use, and has the advantage of in my opinion being simpler and more readable.
My preference is #1 for now unless/until we have a compelling need for #2, but if you or others feel strongly #2 is easy enough to implement.
eth2/simulation/src/simulation.rs
Outdated
) -> Result<EEIndex> { | ||
// Create EE struct from args | ||
let vl_wasm_code = | ||
VariableList::new(a.wasm_code).map_err(|_| Error::MaxLengthExceeded { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to use snafu's ResultExt::context
method for these types of conversions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above -- interested to hear your thoughts on my breakdown of the two options. As mentioned, I have a slight preference for this because it is simpler, uses std library methods, and IMO is more readable.
})?; | ||
|
||
// For each shard, add the initial state to the shard | ||
for shard_state in self.store.current_beacon_state.shard_states.iter_mut() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd like to see a little more encapsulation here. Instead of reaching through multiple levels of struct's internal fields, create some helper methods. Should reduce the amount of duplicate code (especially error conversion.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comment! I don't think I agree for this particular case, though it's possible I'm misunderstanding your point here. What kind of helper function do you envision?
My thoughts:
- I don't expect any code duplication from this sort of thing -- chaining properties like this seems normal and readable, and
current_beacon_state
will always haveshard_states
, etc. - Not sure what you mean by error conversion -- there's no error conversion here. Let me know what I'm missing.
I could see this being applicable in other contexts, is there another line or example that you think could benefit from helper methods?
eth2/simulation/src/simulation.rs
Outdated
let wasm_code: Vec<u8> = execution_environment.wasm_code.clone().into(); | ||
let data: Vec<u8> = transaction.data.clone().into(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to omit the clone calls here, and the conversions to Vec
. VariableList<u8>
implements Deref<Target=[u8]>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, very clever. Thanks for the catch, will update to this.
pub fn new(slot: u64) -> Self { | ||
Self(slot) | ||
} | ||
} | ||
|
||
/// Convert from a hex string to a Root | ||
impl TryFrom<&str> for Root { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FromStr
might be a more idiomatic approach, but I don't think this is incorrect.
|
||
fn try_from(s: &str) -> Result<Self, Self::Error> { | ||
let vec = Vec::from_hex(s).map_err(|e| { | ||
return format!("cannot convert string to hex: {:?}", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Converting an Error
into a String
loses a lot of contextual information. Generally it'd be better to either return the original error type, or convert it to this crate's error type if you don't want to leak dependencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the callout!
This may be me being fairly new to Rust, but I'm not sure I totally agree here. Certainly I agree that returning a string will make it so the underlying Error struct defined by the hex
crate won't get passed along in the return value of try_from
. That said, I think all the relevant context will be there, since the debug print will just print out the underlying error from the hex
crate and include it in the try_from
error message.
I don't feel strongly here at all, but to me it doesn't seem compelling to have the extra logic to either 1) define an Error
type for the eth2/types
library or 2) just return the underlying error from hex
. Seems cleaner, simpler, and just as effective to have it as written.
Interested in reading your response on this :)
eth2/types/src/slot_epoch_root.rs
Outdated
} | ||
} | ||
|
||
impl EEIndex { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EeIndex
would be more standard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, thanks, will change!
.get(ee_index) | ||
.unwrap(); | ||
assert_eq!(ee_state, &expected_post_state); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for all the tests - helps see the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed
This is fantastic. The code is super easy to follow and the tests demonstrate how the interface will be used. The simulation interface is definitely functional, but it would be convenient if I didn't necessarily have to know about SSZ and other spec types in order to interact with it. For example, when calling
or providing a helper method called create_shard_transaction() that accepts some bytes and an index. |
Closing this because all of this is included in #27 |
This commit implements all of the methods from the initial Simulation interface.
Notes:
notion-server/src/ethereum/mod.rs
. In a future diff,notion-server/src/ethereum/mod.rs
will be removed entirely, and the server logic innotion-server
will instead point toeth2/simulation/
.notion-server
(eg. Rocket).Next Steps:
notion-server
to use theSimulation
logic in theeth2/simulation
repository.Simulation
logic fromnotion-server
.notion-server
is working and satisfies all current user needs.notion-server
. This will allow other projects to easily communicate withnotion-server
without needing to "manually" write HTTP requests.notion-server
, SDK, andSimulation
interfaces as-necessary as user needs change.