Skip to content

Commit

Permalink
WIP relative objects
Browse files Browse the repository at this point in the history
  • Loading branch information
graydon committed Jul 13, 2023
1 parent 42980d1 commit 1ce9c6b
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 49 deletions.
2 changes: 1 addition & 1 deletion soroban-env-host/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,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 @@ -1126,7 +1126,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 @@ -1665,7 +1665,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 @@ -1726,7 +1726,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 @@ -1955,7 +1959,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 @@ -1977,7 +1981,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 @@ -2834,8 +2842,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 @@ -2893,7 +2901,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

0 comments on commit 1ce9c6b

Please sign in to comment.