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

Add a helper that invokes a host function 'end-to-end' #964

Merged
merged 3 commits into from
Jul 29, 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
7 changes: 5 additions & 2 deletions soroban-env-host/src/cost_runner/cost_types/val_ser.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::hint::black_box;

use crate::{cost_runner::CostRunner, xdr::ContractCostType, xdr::ScVal};
use crate::{
cost_runner::CostRunner, host::metered_xdr::metered_write_xdr, xdr::ContractCostType,
xdr::ScVal,
};

pub struct ValSerRun;

Expand All @@ -18,7 +21,7 @@ impl CostRunner for ValSerRun {
) -> Self::RecycledType {
// Note the sample.1 is an empty vector, so metered_write_xdr includes allocation
// cost. This is how it's typically used so we are setting it up this way.
black_box(host.metered_write_xdr(&sample.0, &mut sample.1).unwrap());
black_box(metered_write_xdr(host.budget_ref(), &sample.0, &mut sample.1).unwrap());
sample
}

Expand Down
487 changes: 487 additions & 0 deletions soroban-env-host/src/e2e_invoke.rs

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions soroban-env-host/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ use soroban_env_common::xdr::{
ScErrorCode, MASK_CONTRACT_DATA_FLAGS_V20,
};

use self::metered_clone::MeteredClone;
use self::{
frame::{Context, ContractReentryMode},
metered_vector::MeteredVector,
prng::Prng,
};
use self::{metered_clone::MeteredClone, metered_xdr::metered_write_xdr};
use crate::impl_bignum_host_fns;
use crate::Compare;
#[cfg(any(test, feature = "testutils"))]
Expand Down Expand Up @@ -427,15 +427,14 @@ impl Host {
}

/// Accept a _unique_ (refcount = 1) host reference and destroy the
/// underlying [`HostImpl`], returning its constituent components to the
/// caller as a tuple wrapped in `Ok(...)`.
pub fn try_finish(self) -> Result<(Storage, Budget, Events), HostError> {
/// underlying [`HostImpl`], returning its finalized components containing
/// processing side effects to the caller as a tuple wrapped in `Ok(...)`.
pub fn try_finish(self) -> Result<(Storage, Events), HostError> {
let events = self.try_borrow_events()?.externalize(&self)?;
Rc::try_unwrap(self.0)
.map(|host_impl| {
let storage = host_impl.storage.into_inner();
let budget = host_impl.budget;
(storage, budget, events)
(storage, events)
})
.map_err(|_| {
Error::from_type_and_code(ScErrorType::Context, ScErrorCode::InternalError).into()
Expand Down Expand Up @@ -552,7 +551,7 @@ impl Host {
) -> Result<(), HostError> {
if let ContractIdPreimage::Asset(asset) = id_preimage {
let mut asset_bytes: Vec<u8> = Default::default();
self.metered_write_xdr(asset, &mut asset_bytes)?;
metered_write_xdr(self.budget_ref(), asset, &mut asset_bytes)?;
self.call_n_internal(
contract_id,
Symbol::try_from_val(self, &"init_asset")?,
Expand Down Expand Up @@ -2389,7 +2388,7 @@ impl VmCallerEnv for Host {
) -> Result<BytesObject, HostError> {
let scv = self.from_host_val(v)?;
let mut buf = Vec::<u8>::new();
self.metered_write_xdr(&scv, &mut buf)?;
metered_write_xdr(self.budget_ref(), &scv, &mut buf)?;
self.add_host_object(self.scbytes_from_vec(buf)?)
}

Expand Down
10 changes: 9 additions & 1 deletion soroban-env-host/src/host/declared_size.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::rc::Rc;

use soroban_env_common::xdr::SorobanAuthorizationEntry;

use crate::{
events::{EventError, HostEvent, InternalContractEvent, InternalEvent},
host::Events,
Expand Down Expand Up @@ -147,7 +149,7 @@ impl_declared_size_type!(ContractEntryBodyType, 4);
impl_declared_size_type!(ExtensionPoint, 0);
impl_declared_size_type!(SorobanAuthorizedInvocation, 128);
impl_declared_size_type!(ScContractInstance, 64);

impl_declared_size_type!(SorobanAuthorizationEntry, 240);
// composite types

// Rc is an exception, nothing is being cloned. We approximate ref counter bump with the cost of
Expand Down Expand Up @@ -338,6 +340,11 @@ mod test {
expect!["8"].assert_eq(size_of::<Rc<ScVal>>().to_string().as_str());
expect!["64"].assert_eq(size_of::<Option<ScVal>>().to_string().as_str());
expect!["64"].assert_eq(size_of::<ScContractInstance>().to_string().as_str());
expect!["240"].assert_eq(
size_of::<SorobanAuthorizedInvocation>()
.to_string()
.as_str(),
);
}

// This is the actual test.
Expand Down Expand Up @@ -460,6 +467,7 @@ mod test {
assert_mem_size_le_declared_size!(ContractEntryBodyType);
assert_mem_size_le_declared_size!(ExtensionPoint);
assert_mem_size_le_declared_size!(SorobanAuthorizedInvocation);
assert_mem_size_le_declared_size!(SorobanAuthorizationEntry);
// composite types
assert_mem_size_le_declared_size!(&[ScVal]);
assert_mem_size_le_declared_size!((Val, ScVal));
Expand Down
3 changes: 2 additions & 1 deletion soroban-env-host/src/host/metered_clone.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{mem, rc::Rc};

use soroban_env_common::xdr::DepthLimiter;
use soroban_env_common::xdr::{DepthLimiter, SorobanAuthorizationEntry};

use crate::{
budget::Budget,
Expand Down Expand Up @@ -227,6 +227,7 @@ impl MeteredClone for EventError {}
impl MeteredClone for CreateContractArgs {}
impl MeteredClone for ContractIdPreimage {}
impl MeteredClone for SorobanAuthorizedInvocation {}
impl MeteredClone for SorobanAuthorizationEntry {}
// composite types
impl<T> MeteredClone for Rc<T> {}
impl<T> MeteredClone for &[T] {}
Expand Down
55 changes: 34 additions & 21 deletions soroban-env-host/src/host/metered_xdr.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{
budget::Budget,
xdr::ContractCostType,
xdr::{ReadXdr, ScBytes, WriteXdr},
BytesObject, Host, HostError,
Expand All @@ -11,7 +12,7 @@ use soroban_env_common::xdr::{
};

struct MeteredWrite<'a, W: Write> {
host: &'a Host,
budget: &'a Budget,
w: &'a mut W,
}

Expand All @@ -20,8 +21,8 @@ where
W: Write,
{
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.host
.charge_budget(ContractCostType::ValSer, Some(buf.len() as u64))
self.budget
.charge(ContractCostType::ValSer, Some(buf.len() as u64))
.map_err(Into::<std::io::Error>::into)?;
self.w.write(buf)
}
Expand All @@ -32,30 +33,15 @@ where
}

impl Host {
pub(crate) fn metered_write_xdr(
&self,
obj: &impl WriteXdr,
w: &mut Vec<u8>,
) -> Result<(), HostError> {
let _span = tracy_span!("write xdr");
let mw = MeteredWrite { host: self, w };
let mut w = DepthLimitedWrite::new(mw, DEFAULT_XDR_RW_DEPTH_LIMIT);
// MeteredWrite above turned any budget failure into an IO error; we turn it
// back to a budget failure here, since there's really no "IO error" that can
// occur when writing to a Vec<u8>.
obj.write_xdr(&mut w)
.map_err(|_| (ScErrorType::Budget, ScErrorCode::ExceededLimit).into())
}

pub(crate) fn metered_hash_xdr(&self, obj: &impl WriteXdr) -> Result<[u8; 32], HostError> {
pub fn metered_hash_xdr(&self, obj: &impl WriteXdr) -> Result<[u8; 32], HostError> {
let _span = tracy_span!("hash xdr");
let mut buf = vec![];
self.metered_write_xdr(obj, &mut buf)?;
metered_write_xdr(self.budget_ref(), obj, &mut buf)?;
self.charge_budget(ContractCostType::ComputeSha256Hash, Some(buf.len() as u64))?;
Ok(Sha256::digest(&buf).try_into()?)
}

pub(crate) fn metered_from_xdr<T: ReadXdr>(&self, bytes: &[u8]) -> Result<T, HostError> {
pub fn metered_from_xdr<T: ReadXdr>(&self, bytes: &[u8]) -> Result<T, HostError> {
let _span = tracy_span!("read xdr");
self.charge_budget(ContractCostType::ValDeser, Some(bytes.len() as u64))?;
self.map_err(T::from_xdr(bytes))
Expand All @@ -68,3 +54,30 @@ impl Host {
self.visit_obj(bytes, |hv: &ScBytes| self.metered_from_xdr(hv.as_slice()))
}
}

pub fn metered_write_xdr(
budget: &Budget,
obj: &impl WriteXdr,
w: &mut Vec<u8>,
) -> Result<(), HostError> {
let _span = tracy_span!("write xdr");
let mw = MeteredWrite { budget, w };
let mut w = DepthLimitedWrite::new(mw, DEFAULT_XDR_RW_DEPTH_LIMIT);
// MeteredWrite above turned any budget failure into an IO error; we turn it
// back to a budget failure here, since there's really no "IO error" that can
// occur when writing to a Vec<u8>.
obj.write_xdr(&mut w)
.map_err(|_| (ScErrorType::Budget, ScErrorCode::ExceededLimit).into())
}

// Host-less metered XDR decoding.
// Prefer using `metered_from_xdr` when host is available for better error
// reporting.
pub fn metered_from_xdr_with_budget<T: ReadXdr>(
bytes: &[u8],
budget: &Budget,
) -> Result<T, HostError> {
let _span = tracy_span!("read xdr with budget");
budget.charge(ContractCostType::ValDeser, Some(bytes.len() as u64))?;
T::from_xdr(bytes).map_err(|e| e.into())
}
3 changes: 2 additions & 1 deletion soroban-env-host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
//! - The [storage] module which is responsible for providing an interface
//! between contracts and their durable storage.
//!

#![recursion_limit = "256"]
#[cfg(all(not(target_family = "wasm"), feature = "tracy"))]
macro_rules! tracy_span {
() => {
Expand Down Expand Up @@ -71,4 +71,5 @@ pub use host::{
};
pub use soroban_env_common::*;

pub mod e2e_invoke;
pub mod fees;
6 changes: 3 additions & 3 deletions soroban-env-host/src/test/budget_metering.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
budget::AsBudget,
host::metered_clone::MeteredClone,
host::{metered_clone::MeteredClone, metered_xdr::metered_write_xdr},
xdr::{ContractCostType, ScMap, ScMapEntry, ScVal},
Env, Host, HostError, Symbol, Val,
};
Expand Down Expand Up @@ -93,7 +93,7 @@ fn metered_xdr() -> Result<(), HostError> {
.try_into(),
)?;
let mut w = Vec::<u8>::new();
host.metered_write_xdr(&scmap, &mut w)?;
metered_write_xdr(host.budget_ref(), &scmap, &mut w)?;
host.with_budget(|budget| {
assert_eq!(
budget.get_tracker(ContractCostType::ValSer)?.1,
Expand Down Expand Up @@ -133,7 +133,7 @@ fn metered_xdr_out_of_budget() -> Result<(), HostError> {
.try_into(),
)?;
let mut w = Vec::<u8>::new();
let res = host.metered_write_xdr(&scmap, &mut w);
let res = metered_write_xdr(host.budget_ref(), &scmap, &mut w);
let code = (ScErrorType::Budget, ScErrorCode::ExceededLimit);
assert!(HostError::result_matches_err(res, code));
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion soroban-env-host/src/test/complex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ fn run_complex() -> Result<(), HostError> {
Symbol::try_from_small_str("go")?,
host.add_host_object(HostVec::new())?,
)?;
let (store, _, _) = host.try_finish().unwrap();
let (store, _) = host.try_finish().unwrap();
store.footprint
};

Expand Down
4 changes: 2 additions & 2 deletions soroban-env-host/src/test/metering_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn run_add_i32() -> Result<(), HostError> {
Symbol::try_from_small_str("add")?,
host.test_vec_obj(&[a, b])?,
)?;
let (store, _, _) = host.try_finish().unwrap();
let (store, _) = host.try_finish().unwrap();
store.footprint
};
// Run 2: enforce preflight footprint
Expand Down Expand Up @@ -91,7 +91,7 @@ fn run_complex() -> Result<(), HostError> {
Symbol::try_from_small_str("go")?,
host.add_host_object(HostVec::new())?,
)?;
let (store, _, _) = host.try_finish().unwrap();
let (store, _) = host.try_finish().unwrap();
store.footprint
};

Expand Down