-
Notifications
You must be signed in to change notification settings - Fork 79
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
EVM runtime: implement GetBytecode and GetStorageAt getters. #631
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ use { | |
crate::interpreter::{execute, Bytecode, ExecutionState, StatusCode, System, U256}, | ||
crate::state::State, | ||
bytes::Bytes, | ||
cid::Cid, | ||
fil_actors_runtime::{ | ||
actor_error, cbor, | ||
runtime::{ActorCode, Runtime}, | ||
|
@@ -32,6 +33,8 @@ const MAX_CODE_SIZE: usize = 24 << 10; | |
pub enum Method { | ||
Constructor = METHOD_CONSTRUCTOR, | ||
InvokeContract = 2, | ||
GetBytecode = 3, | ||
GetStorageAt = 4, | ||
} | ||
|
||
pub struct EvmContractActor; | ||
|
@@ -173,6 +176,48 @@ impl EvmContractActor { | |
let output = RawBytes::from(exec_status.output_data.to_vec()); | ||
Ok(output) | ||
} | ||
|
||
pub fn bytecode<BS, RT>(rt: &mut RT) -> Result<Cid, ActorError> | ||
where | ||
BS: Blockstore + Clone, | ||
RT: Runtime<BS>, | ||
{ | ||
// Any caller can fetch the bytecode of a contract; this is now EXT* opcodes work. | ||
rt.validate_immediate_caller_accept_any()?; | ||
|
||
let state: State = rt.state()?; | ||
Ok(state.bytecode) | ||
} | ||
|
||
pub fn storage_at<BS, RT>(rt: &mut RT, params: GetStorageAtParams) -> Result<U256, ActorError> | ||
where | ||
BS: Blockstore + Clone, | ||
RT: Runtime<BS>, | ||
{ | ||
// This method cannot be called on-chain; other on-chain logic should not be able to | ||
// access arbitrary storage keys from a contract. | ||
rt.validate_immediate_caller_is([&fvm_shared::address::Address::new_id(0)])?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This very funky, we have an effectively uncallable method. Thats one extra reason to expect the client to directly read the state, or it should be a non method entry point. Having said that, it is totally fine for now, but we should think about this general pattern. |
||
|
||
let state: State = rt.state()?; | ||
let blockstore = rt.store().clone(); | ||
|
||
// load the storage HAMT | ||
let mut hamt = | ||
Hamt::<_, _, U256>::load(&state.contract_state, blockstore).map_err(|e| { | ||
ActorError::illegal_state(format!( | ||
"failed to load storage HAMT on invoke: {e:?}, e" | ||
)) | ||
})?; | ||
|
||
let mut system = System::new(rt, &mut hamt).map_err(|e| { | ||
ActorError::unspecified(format!("failed to create execution abstraction layer: {e:?}")) | ||
})?; | ||
Comment on lines
+204
to
+214
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like we need to do this a lot. Helper? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should probably make one, but that's out of scope here. I would like to do a general cleanup/beatify pass at some point. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. btw, feel free to go wild and apply bigclaw magic in the code when there is a lull. |
||
|
||
system | ||
.get_storage(params.storage_key) | ||
.map_err(|st| ActorError::unspecified(format!("failed to get storage key: {}", &st)))? | ||
.ok_or_else(|| ActorError::not_found(String::from("storage key not found"))) | ||
} | ||
} | ||
|
||
impl ActorCode for EvmContractActor { | ||
|
@@ -193,6 +238,14 @@ impl ActorCode for EvmContractActor { | |
Some(Method::InvokeContract) => { | ||
Self::invoke_contract(rt, cbor::deserialize_params(params)?) | ||
} | ||
Some(Method::GetBytecode) => { | ||
let cid = Self::bytecode(rt)?; | ||
Ok(RawBytes::serialize(cid)?) | ||
} | ||
Some(Method::GetStorageAt) => { | ||
let value = Self::storage_at(rt, cbor::deserialize_params(params)?)?; | ||
Ok(RawBytes::serialize(value)?) | ||
} | ||
None => Err(actor_error!(unhandled_message; "Invalid method")), | ||
} | ||
} | ||
|
@@ -208,3 +261,8 @@ pub struct ConstructorParams { | |
pub struct InvokeParams { | ||
pub input_data: RawBytes, | ||
} | ||
|
||
#[derive(Serialize_tuple, Deserialize_tuple)] | ||
pub struct GetStorageAtParams { | ||
pub storage_key: U256, | ||
} |
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.
nit:
this is now
->this is how