Skip to content

Commit

Permalink
Implement contract instance storage in Soroban host. (#886)
Browse files Browse the repository at this point in the history
* Implement contract instance storage in Soroban host.

Also use instance storage in built-in token contract for instance data (metadata, admin, asset info)

* Update soroban-env-host/src/host.rs

* !fixup use sample to pass empty contract instance to benchmark

* !fixup Make instance storage crate-private

It's not intended to be used outside of the host.

* Add smoke tests for rent bumps

---------

Co-authored-by: Siddharth Suresh <[email protected]>
  • Loading branch information
dmkozh and sisuresh authored Jun 24, 2023
1 parent 035af74 commit a9dbd06
Show file tree
Hide file tree
Showing 38 changed files with 783 additions and 432 deletions.
13 changes: 8 additions & 5 deletions soroban-env-common/src/storage_type.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use num_derive::FromPrimitive;
use stellar_xdr::ContractDataDurability;

use crate::declare_wasmi_marshal_for_enum;
use crate::{declare_wasmi_marshal_for_enum, ConversionError};

/// This is just a distinct enum local to the env interface that is used as
/// an argument to storage functions. It doesn't correspond to any [`Val`] types,
Expand All @@ -14,11 +14,14 @@ pub enum StorageType {
Instance = 2,
}

impl From<StorageType> for ContractDataDurability {
fn from(value: StorageType) -> Self {
impl TryFrom<StorageType> for ContractDataDurability {
type Error = ConversionError;

fn try_from(value: StorageType) -> Result<Self, Self::Error> {
match value {
StorageType::Temporary => ContractDataDurability::Temporary,
StorageType::Persistent | StorageType::Instance => ContractDataDurability::Persistent,
StorageType::Temporary => Ok(ContractDataDurability::Temporary),
StorageType::Persistent => Ok(ContractDataDurability::Persistent),
StorageType::Instance => Err(ConversionError {}),
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion soroban-env-host/benches/common/cost_types/guard_frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ impl HostCostMeasurement for GuardFrameMeasure {
) -> (Hash, Symbol) {
let id: Hash = [0; 32].into();
let fun: Symbol = Symbol::try_from_small_str("add").unwrap();
(id, fun)
let empty_instance = ScContractInstance {
executable: ContractExecutable::Token,
storage: None,
};
(id, fun, empty_instance)
}

fn new_random_case(
Expand Down
4 changes: 2 additions & 2 deletions soroban-env-host/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ impl AuthorizationManager {
// This should be called for every `Host` `push_frame`.
pub(crate) fn push_frame(&mut 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 All @@ -701,7 +701,7 @@ impl AuthorizationManager {
// `push_create_contract_host_fn_frame`) functions instead to push
// the frame with the required info.
Frame::HostFunction(_) => return Ok(()),
Frame::Token(id, fn_name, _) => (id.metered_clone(host.budget_ref())?, *fn_name),
Frame::Token(id, fn_name, ..) => (id.metered_clone(host.budget_ref())?, *fn_name),
#[cfg(any(test, feature = "testutils"))]
Frame::TestContract(tc) => (tc.id.clone(), tc.func),
};
Expand Down
6 changes: 4 additions & 2 deletions soroban-env-host/src/cost_runner/cost_types/guard_frame.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
use std::hint::black_box;

use soroban_env_common::xdr::ScContractInstance;

use crate::{cost_runner::CostRunner, host::Frame, xdr::ContractCostType, xdr::Hash, Symbol, Val};

pub struct GuardFrameRun;

impl CostRunner for GuardFrameRun {
const COST_TYPE: ContractCostType = ContractCostType::GuardFrame;

type SampleType = (Hash, Symbol);
type SampleType = (Hash, Symbol, ScContractInstance);

type RecycledType = Option<Self::SampleType>;

fn run_iter(host: &crate::Host, _iter: u64, sample: Self::SampleType) -> Self::RecycledType {
black_box(
host.with_frame(Frame::Token(sample.0, sample.1, vec![]), || {
host.with_frame(Frame::Token(sample.0, sample.1, vec![], sample.2), || {
Ok(Val::VOID.to_val())
})
.unwrap(),
Expand Down
4 changes: 2 additions & 2 deletions soroban-env-host/src/events/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ 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())),
Some(Frame::Token(id, ..)) => Ok(Some(id.clone())),
#[cfg(any(test, feature = "testutils"))]
Some(Frame::TestContract(tc)) => Ok(Some(tc.id.clone())),
None => Ok(None),
Expand Down
Loading

0 comments on commit a9dbd06

Please sign in to comment.