Skip to content
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

Relative objects in wasm #947

Merged
merged 4 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion soroban-env-host/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,7 @@ impl AuthorizationManager {
// This should be called for every `Host` `push_frame`.
pub(crate) fn push_frame(&self, host: &Host, frame: &Frame) -> Result<(), HostError> {
let (contract_id, function_name) = match frame {
Frame::ContractVM(vm, fn_name, ..) => {
Frame::ContractVM { vm, fn_name, .. } => {
(vm.contract_id.metered_clone(host.budget_ref())?, *fn_name)
}
// Skip the top-level host function stack frames as they don't
Expand Down
2 changes: 1 addition & 1 deletion soroban-env-host/src/events/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl Host {
// Will not return error if frame is missing
pub(crate) fn get_current_contract_id_unmetered(&self) -> Result<Option<Hash>, HostError> {
self.with_current_frame_opt(|frame| match frame {
Some(Frame::ContractVM(vm, ..)) => Ok(Some(vm.contract_id.clone())),
Some(Frame::ContractVM { vm, .. }) => Ok(Some(vm.contract_id.clone())),
Some(Frame::HostFunction(_)) => Ok(None),
Some(Frame::Token(id, ..)) => Ok(Some(id.clone())),
#[cfg(any(test, feature = "testutils"))]
Expand Down
24 changes: 16 additions & 8 deletions soroban-env-host/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,7 +1140,7 @@ impl VmCallerEnv for Host {
&vm,
pos,
vals.as_mut_slice(),
|buf| Val::from_payload(u64::from_le_bytes(*buf)),
|buf| self.relative_to_absolute(Val::from_payload(u64::from_le_bytes(*buf))),
)?;

self.log_diagnostics(&msg, &vals)
Expand Down Expand Up @@ -1679,7 +1679,7 @@ impl VmCallerEnv for Host {
&vm,
vals_pos,
vals.as_mut_slice(),
|buf| Val::from_payload(u64::from_le_bytes(*buf)),
|buf| self.relative_to_absolute(Val::from_payload(u64::from_le_bytes(*buf))),
)?;
for v in vals.iter() {
self.check_val_integrity(*v)?;
Expand Down Expand Up @@ -1740,7 +1740,11 @@ impl VmCallerEnv for Host {
&vm,
vals_pos.into(),
mapobj.map.as_slice(),
|pair| u64::to_le_bytes(pair.1.get_payload()),
|pair| {
Ok(u64::to_le_bytes(
self.absolute_to_relative(pair.1)?.get_payload(),
))
},
)?;
Ok(())
})?;
Expand Down Expand Up @@ -1969,7 +1973,7 @@ impl VmCallerEnv for Host {
&vm,
pos,
vals.as_mut_slice(),
|buf| Val::from_payload(u64::from_le_bytes(*buf)),
|buf| self.relative_to_absolute(Val::from_payload(u64::from_le_bytes(*buf))),
)?;
for v in vals.iter() {
self.check_val_integrity(*v)?;
Expand All @@ -1991,7 +1995,11 @@ impl VmCallerEnv for Host {
&vm,
vals_pos.into(),
vecobj.as_slice(),
|x| u64::to_le_bytes(x.get_payload()),
|x| {
Ok(u64::to_le_bytes(
self.absolute_to_relative(*x)?.get_payload(),
))
},
)
})?;
Ok(Val::VOID)
Expand Down Expand Up @@ -2848,8 +2856,8 @@ impl VmCallerEnv for Host {
let mut outer = Vec::with_capacity(contexts.len());
for context in contexts.iter() {
let vals = match &context.frame {
Frame::ContractVM(vm, function, ..) => {
get_host_val_tuple(&vm.contract_id, &function)?
Frame::ContractVM { vm, fn_name, .. } => {
get_host_val_tuple(&vm.contract_id, fn_name)?
}
Frame::HostFunction(_) => continue,
Frame::Token(id, function, ..) => get_host_val_tuple(id, function)?,
Expand Down Expand Up @@ -2907,7 +2915,7 @@ impl VmCallerEnv for Host {
) -> Result<Void, Self::Error> {
let args = self.with_current_frame(|f| {
let args = match f {
Frame::ContractVM(_, _, args, _) => args,
Frame::ContractVM { args, .. } => args,
Frame::HostFunction(_) => {
return Err(self.err(
ScErrorType::Context,
Expand Down
61 changes: 49 additions & 12 deletions soroban-env-host/src/host/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
err,
storage::{InstanceStorageMap, StorageMap},
xdr::{ContractCostType, ContractExecutable, Hash, HostFunction, HostFunctionType, ScVal},
Error, Host, HostError, Symbol, SymbolStr, TryFromVal, TryIntoVal, Val,
Error, Host, HostError, Object, Symbol, SymbolStr, TryFromVal, TryIntoVal, Val,
};

#[cfg(any(test, feature = "testutils"))]
Expand Down Expand Up @@ -104,7 +104,13 @@ pub(crate) struct Context {
/// commit or roll back that state when it pops the stack.
#[derive(Clone)]
pub(crate) enum Frame {
ContractVM(Rc<Vm>, Symbol, Vec<Val>, ScContractInstance),
ContractVM {
vm: Rc<Vm>,
fn_name: Symbol,
args: Vec<Val>,
instance: ScContractInstance,
relative_objects: Vec<Object>,
},
HostFunction(HostFunctionType),
Token(Hash, Symbol, Vec<Val>, ScContractInstance),
#[cfg(any(test, feature = "testutils"))]
Expand Down Expand Up @@ -246,6 +252,30 @@ impl Host {
}
}

pub(crate) fn with_current_frame_relative_object_table<F, U>(
&self,
f: F,
) -> Result<U, HostError>
where
F: FnOnce(&mut Vec<Object>) -> Result<U, HostError>,
{
self.with_current_context_mut(|ctx| {
if let Frame::ContractVM {
relative_objects, ..
} = &mut ctx.frame
{
f(relative_objects)
} else {
Err(self.err(
ScErrorType::Context,
ScErrorCode::InternalError,
"accessing relative object table in non-VM frame",
&[],
))
}
})
}

pub(crate) fn with_current_prng<F, U>(&self, f: F) -> Result<U, HostError>
where
F: FnOnce(&mut Prng) -> Result<U, HostError>,
Expand Down Expand Up @@ -327,7 +357,7 @@ impl Host {
/// frame at its top.
pub(crate) fn get_current_contract_id_opt_internal(&self) -> Result<Option<Hash>, HostError> {
self.with_current_frame(|frame| match frame {
Frame::ContractVM(vm, ..) => Ok(Some(vm.contract_id.metered_clone(&self.0.budget)?)),
Frame::ContractVM { vm, .. } => Ok(Some(vm.contract_id.metered_clone(&self.0.budget)?)),
Frame::HostFunction(_) => Ok(None),
Frame::Token(id, ..) => Ok(Some(id.metered_clone(&self.0.budget)?)),
#[cfg(any(test, feature = "testutils"))]
Expand Down Expand Up @@ -356,7 +386,7 @@ impl Host {
// the previous frame must exist and must be a contract
let hash = match frames.as_slice() {
[.., c2, _] => match &c2.frame {
Frame::ContractVM(vm, ..) => Ok(vm.contract_id.metered_clone(&self.0.budget)?),
Frame::ContractVM { vm, .. } => Ok(vm.contract_id.metered_clone(&self.0.budget)?),
Frame::HostFunction(_) => Err(self.err(
ScErrorType::Context,
ScErrorCode::UnexpectedType,
Expand Down Expand Up @@ -385,7 +415,7 @@ impl Host {
let st = match frames.as_slice() {
// There are always two frames when WASM is executed in the VM.
[.., c2, _] => match &c2.frame {
Frame::ContractVM(..) => Ok(InvokerType::Contract),
Frame::ContractVM { .. } => Ok(InvokerType::Contract),
Frame::HostFunction(_) => Ok(InvokerType::Account),
Frame::Token(..) => Ok(InvokerType::Contract),
#[cfg(any(test, feature = "testutils"))]
Expand Down Expand Up @@ -428,22 +458,29 @@ impl Host {
fn call_contract_fn(&self, id: &Hash, func: &Symbol, args: &[Val]) -> Result<Val, HostError> {
// Create key for storage
let storage_key = self.contract_instance_ledger_key(id)?;
let contract_instance = self.retrieve_contract_instance_from_storage(&storage_key)?;
match &contract_instance.executable {
let instance = self.retrieve_contract_instance_from_storage(&storage_key)?;
match &instance.executable {
ContractExecutable::Wasm(wasm_hash) => {
let code_entry = self.retrieve_wasm_from_storage(&wasm_hash)?;
let vm = Vm::new(
self,
id.metered_clone(&self.0.budget)?,
code_entry.as_slice(),
)?;
let relative_objects = Vec::new();
self.with_frame(
Frame::ContractVM(vm.clone(), *func, args.to_vec(), contract_instance),
Frame::ContractVM {
vm: vm.clone(),
fn_name: *func,
args: args.to_vec(),
instance,
relative_objects,
},
|| vm.invoke_function_raw(self, func, args),
)
}
ContractExecutable::Token => self.with_frame(
Frame::Token(id.clone(), *func, args.to_vec(), contract_instance),
Frame::Token(id.clone(), *func, args.to_vec(), instance),
|| {
use crate::native_contract::{NativeContract, Token};
Token.call(func, self, args)
Expand Down Expand Up @@ -480,7 +517,7 @@ impl Host {
let mut is_last_non_host_frame = true;
for ctx in self.try_borrow_context()?.iter().rev() {
let exist_id = match &ctx.frame {
Frame::ContractVM(vm, ..) => &vm.contract_id,
Frame::ContractVM { vm, .. } => &vm.contract_id,
Frame::Token(id, ..) => id,
#[cfg(any(test, feature = "testutils"))]
Frame::TestContract(tc) => &tc.id,
Expand Down Expand Up @@ -683,7 +720,7 @@ impl Host {
return Ok(());
}
let storage_map = match &ctx.frame {
Frame::ContractVM(_, _, _, instance) => &instance.storage,
Frame::ContractVM { instance, .. } => &instance.storage,
Frame::HostFunction(_) => {
return Err(self.err(
ScErrorType::Context,
Expand Down Expand Up @@ -722,7 +759,7 @@ impl Host {
return Ok(None);
}
let executable = match &ctx.frame {
Frame::ContractVM(_, _, _, instance) => {
Frame::ContractVM { instance, .. } => {
instance.executable.metered_clone(self.budget_ref())?
}
Frame::HostFunction(_) => {
Expand Down
10 changes: 5 additions & 5 deletions soroban-env-host/src/host/mem_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Host {
let pos: u32 = pos.into();
let len: u32 = len.into();
self.with_current_frame(|frame| match frame {
Frame::ContractVM(vm, ..) => {
Frame::ContractVM { vm, .. } => {
let vm = vm.clone();
Ok(VmSlice { vm, pos, len })
}
Expand Down Expand Up @@ -67,7 +67,7 @@ impl Host {
vm: &Rc<Vm>,
mem_pos: u32,
buf: &[VAL],
to_le_bytes: impl Fn(&VAL) -> [u8; VAL_SZ],
to_le_bytes: impl Fn(&VAL) -> Result<[u8; VAL_SZ], HostError>,
) -> Result<(), HostError> {
let val_sz = self.usize_to_u32(VAL_SZ)?;
let len = self.usize_to_u32(buf.len())?;
Expand Down Expand Up @@ -96,7 +96,7 @@ impl Host {
&[],
));
}
let tmp: [u8; VAL_SZ] = to_le_bytes(src);
let tmp: [u8; VAL_SZ] = to_le_bytes(src)?;
dst.copy_from_slice(&tmp);
}
Ok(())
Expand All @@ -108,7 +108,7 @@ impl Host {
vm: &Rc<Vm>,
mem_pos: u32,
buf: &mut [VAL],
from_le_bytes: impl Fn(&[u8; VAL_SZ]) -> VAL,
from_le_bytes: impl Fn(&[u8; VAL_SZ]) -> Result<VAL, HostError>,
) -> Result<(), HostError> {
let val_sz = self.usize_to_u32(VAL_SZ)?;
let len = self.usize_to_u32(buf.len())?;
Expand All @@ -131,7 +131,7 @@ impl Host {
for (dst, src) in buf.iter_mut().zip(mem_slice.chunks(VAL_SZ)) {
if let Ok(src) = TryInto::<&[u8; VAL_SZ]>::try_into(src) {
tmp.copy_from_slice(src);
*dst = from_le_bytes(&tmp);
*dst = from_le_bytes(&tmp)?;
} else {
// This should be impossible unless there's an error above, but just in case.
return Err(self.err(
Expand Down
Loading