Skip to content

Commit

Permalink
Refactor host to support the new expiration ledger approach.
Browse files Browse the repository at this point in the history
- Pass expiration ledgers as side input to the ledger entries (temporarily set `expiration_ledger_seq` to 0 until it's removed from XDR)
- Get rid of the autobump support.
  • Loading branch information
dmkozh committed Aug 24, 2023
1 parent ee38966 commit fc02733
Show file tree
Hide file tree
Showing 49 changed files with 822 additions and 1,031 deletions.
508 changes: 321 additions & 187 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ soroban-native-sdk-macros = { version = "0.0.17", path = "soroban-native-sdk-mac
[workspace.dependencies.stellar-xdr]
version = "0.0.17"
git = "https://github.com/stellar/rs-stellar-xdr"
rev = "e2a9cbf72d94941de1bde6ba34a38e1f49328567"
rev = "936273b737b99d79eee7a28dd4823436d0bd0abb"
default-features = false

[workspace.dependencies.wasmi]
Expand Down
7 changes: 1 addition & 6 deletions soroban-env-common/env.json
Original file line number Diff line number Diff line change
Expand Up @@ -1237,14 +1237,9 @@
{
"name": "t",
"type": "StorageType"
},
{
"name": "f",
"type": "Val"
}
],
"return": "Void",
"docs": "If `f` is `Void`, then there will be no changes to flags for an existing entry, and none will be set if this is a new entry. Otherwise, `f` is parsed as a `u32`. If the value is 0, then all flags are cleared. If it's not 0, then flags will be set to the passed in value."
"return": "Void"
},
{
"export": "0",
Expand Down
2 changes: 1 addition & 1 deletion soroban-env-common/src/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub const ENV_META_V0_SECTION_NAME: &str = "contractenvmetav0";

soroban_env_macros::generate_env_meta_consts!(
ledger_protocol_version: 20,
pre_release_version: 55,
pre_release_version: 56,
);

pub fn get_ledger_protocol_version(interface_version: u64) -> u32 {
Expand Down
17 changes: 7 additions & 10 deletions soroban-env-host/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use std::rc::Rc;

use rand::Rng;
use soroban_env_common::xdr::{
ContractDataEntry, ContractDataEntryBody, ContractDataEntryData, CreateContractArgs,
HashIdPreimage, HashIdPreimageSorobanAuthorization, InvokeContractArgs, LedgerEntry,
LedgerEntryData, LedgerEntryExt, ScAddress, ScErrorCode, ScErrorType, ScNonceKey, ScVal,
SorobanAuthorizationEntry, SorobanAuthorizedFunction, SorobanCredentials,
ContractDataEntry, CreateContractArgs, HashIdPreimage, HashIdPreimageSorobanAuthorization,
InvokeContractArgs, LedgerEntry, LedgerEntryData, LedgerEntryExt, ScAddress, ScErrorCode,
ScErrorType, ScNonceKey, ScVal, SorobanAuthorizationEntry, SorobanAuthorizedFunction,
SorobanCredentials,
};
use soroban_env_common::{AddressObject, Compare, Symbol, TryFromVal, TryIntoVal, Val, VecObject};

Expand Down Expand Up @@ -1776,16 +1776,12 @@ impl Host {
&[address.into()],
));
}
let body = ContractDataEntryBody::DataEntry(ContractDataEntryData {
val: ScVal::Void,
flags: 0,
});
let data = LedgerEntryData::ContractData(ContractDataEntry {
contract: sc_address,
key: nonce_key_scval,
body,
expiration_ledger_seq: expiration_ledger,
val: ScVal::Void,
durability: xdr::ContractDataDurability::Temporary,
ext: xdr::ExtensionPoint::V0,
});
let entry = LedgerEntry {
last_modified_ledger_seq: 0,
Expand All @@ -1795,6 +1791,7 @@ impl Host {
storage.put(
&nonce_key,
&Rc::metered_new(entry, self)?,
Some(expiration_ledger),
self.budget_ref(),
)
})
Expand Down
91 changes: 30 additions & 61 deletions soroban-env-host/src/e2e_invoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ use std::{cmp::max, rc::Rc};

use soroban_env_common::{
xdr::{
AccountId, ContractCodeEntryBody, ContractDataDurability, ContractDataEntryBody,
ContractEntryBodyType, ContractEventType, DiagnosticEvent, HostFunction, LedgerEntry,
LedgerEntryData, LedgerFootprint, LedgerKey, LedgerKeyAccount, LedgerKeyContractCode,
LedgerKeyContractData, LedgerKeyTrustLine, ScErrorCode, ScErrorType,
AccountId, ContractDataDurability, ContractEventType, DiagnosticEvent, HostFunction,
LedgerEntry, LedgerEntryData, LedgerFootprint, LedgerKey, LedgerKeyAccount,
LedgerKeyContractCode, LedgerKeyContractData, LedgerKeyTrustLine, ScErrorCode, ScErrorType,
SorobanAuthorizationEntry, SorobanResources,
},
Error,
Expand All @@ -20,7 +19,7 @@ use crate::{
events::Events,
fees::LedgerEntryRentChange,
host::{
ledger_info_helper::{get_entry_expiration, get_key_durability, set_entry_expiration},
ledger_info_helper::get_key_durability,
metered_clone::{MeteredAlloc, MeteredClone, MeteredIterator},
metered_xdr::{metered_from_xdr_with_budget, metered_write_xdr},
},
Expand Down Expand Up @@ -99,7 +98,7 @@ pub fn get_ledger_changes<T: SnapshotSource>(
// happen in embedder environments, or simply fundamental invariant bugs.
let internal_error: HostError =
Error::from_type_and_code(ScErrorType::Storage, ScErrorCode::InternalError).into();
for (key, entry) in storage.map.iter(budget)? {
for (key, entry_with_expiration) in storage.map.iter(budget)? {
let mut entry_change = LedgerEntryChange::default();
metered_write_xdr(budget, key.as_ref(), &mut entry_change.encoded_key)?;
let durability = get_key_durability(key);
Expand All @@ -111,22 +110,21 @@ pub fn get_ledger_changes<T: SnapshotSource>(
});
}
if init_storage_snapshot.has(key)? {
let old_entry = init_storage_snapshot.get(key)?;
let (old_entry, old_expiration) = init_storage_snapshot.get(key)?;
let mut buf = vec![];
metered_write_xdr(budget, old_entry.as_ref(), &mut buf)?;
entry_change.old_entry_size_bytes = buf.len() as u32;

if let Some(ref mut expiration_change) = &mut entry_change.expiration_change {
expiration_change.old_expiration_ledger = get_entry_expiration(old_entry.as_ref())
.ok_or_else(|| internal_error.clone())?;
expiration_change.old_expiration_ledger =
old_expiration.ok_or_else(|| internal_error.clone())?;
}
}
if let Some(entry) = entry {
if let Some((_, new_expiration_ledger)) = entry_with_expiration {
if let Some(ref mut expiration_change) = &mut entry_change.expiration_change {
// Never reduce the expiration ledger. This is also handled when
// processing RW entries.
// Never reduce the final expiration ledger.
expiration_change.new_expiration_ledger = max(
get_entry_expiration(entry.as_ref()).ok_or_else(|| internal_error.clone())?,
new_expiration_ledger.ok_or_else(|| internal_error.clone())?,
expiration_change.old_expiration_ledger,
);
}
Expand All @@ -138,30 +136,10 @@ pub fn get_ledger_changes<T: SnapshotSource>(
entry_change.read_only = true;
}
Some(AccessType::ReadWrite) => {
if let Some(entry) = entry {
// Handle the edge case where due to combinations of
// deletions/creations the entry expiration has been
// reduced.
let mut entry_written = false;
if let (Some(expiration_change), Some(new_expiration)) = (
&entry_change.expiration_change,
get_entry_expiration(entry.as_ref()),
) {
if expiration_change.old_expiration_ledger > new_expiration {
let mut new_entry: LedgerEntry =
entry.as_ref().metered_clone(budget)?;
set_entry_expiration(&mut new_entry, new_expiration);
let mut entry_buf = vec![];
metered_write_xdr(budget, &new_entry, &mut entry_buf)?;
entry_change.encoded_new_value = Some(entry_buf);
entry_written = true;
}
}
if !entry_written {
let mut entry_buf = vec![];
metered_write_xdr(budget, entry.as_ref(), &mut entry_buf)?;
entry_change.encoded_new_value = Some(entry_buf);
}
if let Some((entry, _)) = entry_with_expiration {
let mut entry_buf = vec![];
metered_write_xdr(budget, entry.as_ref(), &mut entry_buf)?;
entry_change.encoded_new_value = Some(entry_buf);
}
}
None => {
Expand Down Expand Up @@ -236,15 +214,19 @@ pub fn extract_rent_changes(ledger_changes: &Vec<LedgerEntryChange>) -> Vec<Ledg
/// When diagnostics are enabled, we try to populate `diagnostic_events`
/// even if the `InvokeHostFunctionResult` fails for any reason.
#[allow(clippy::too_many_arguments)]
pub fn invoke_host_function<T: AsRef<[u8]>, I: ExactSizeIterator<Item = T>>(
pub fn invoke_host_function<
T: AsRef<[u8]>,
I: ExactSizeIterator<Item = T>,
EntryIter: ExactSizeIterator<Item = (T, Option<u32>)>,
>(
budget: &Budget,
enable_diagnostics: bool,
encoded_host_fn: T,
encoded_resources: T,
encoded_source_account: T,
encoded_auth_entries: I,
ledger_info: LedgerInfo,
encoded_ledger_entries: I,
encoded_ledger_entries: EntryIter,
base_prng_seed: T,
diagnostic_events: &mut Vec<DiagnosticEvent>,
) -> Result<InvokeHostFunctionResult, HostError> {
Expand Down Expand Up @@ -366,25 +348,9 @@ fn ledger_entry_to_ledger_key(le: &LedgerEntry, budget: &Budget) -> Result<Ledge
contract: cd.contract.metered_clone(budget)?,
key: cd.key.metered_clone(budget)?,
durability: cd.durability,
body_type: match &cd.body {
ContractDataEntryBody::DataEntry(_data) => ContractEntryBodyType::DataEntry,
ContractDataEntryBody::ExpirationExtension => {
ContractEntryBodyType::ExpirationExtension
}
},
})),
LedgerEntryData::ContractCode(code) => Ok(LedgerKey::ContractCode(LedgerKeyContractCode {
hash: code.hash.metered_clone(budget)?,
body_type: match &code.body {
ContractCodeEntryBody::DataEntry(_) => ContractEntryBodyType::DataEntry,
ContractCodeEntryBody::ExpirationExtension => {
return Err(Error::from_type_and_code(
ScErrorType::Storage,
ScErrorCode::InternalError,
)
.into());
}
},
})),
_ => {
return Err(Error::from_type_and_code(
Expand Down Expand Up @@ -422,13 +388,16 @@ fn build_storage_footprint_from_xdr(
Ok(Footprint(footprint_map))
}

fn build_storage_map_from_xdr_ledger_entries<T: AsRef<[u8]>, I: ExactSizeIterator<Item = T>>(
fn build_storage_map_from_xdr_ledger_entries<
T: AsRef<[u8]>,
I: ExactSizeIterator<Item = (T, Option<u32>)>,
>(
budget: &Budget,
footprint: &Footprint,
encoded_ledger_entries: I,
) -> Result<StorageMap, HostError> {
let mut map = StorageMap::new();
for buf in encoded_ledger_entries {
for (buf, expiration_ledger) in encoded_ledger_entries {
let le = Rc::metered_new(
metered_from_xdr_with_budget::<LedgerEntry>(buf.as_ref(), budget)?,
budget,
Expand All @@ -441,7 +410,7 @@ fn build_storage_map_from_xdr_ledger_entries<T: AsRef<[u8]>, I: ExactSizeIterato
)
.into());
}
map = map.insert(key, Some(le), budget)?;
map = map.insert(key, Some((le, expiration_ledger)), budget)?;
}

// Add non-existing entries from the footprint to the storage.
Expand Down Expand Up @@ -472,9 +441,9 @@ struct StorageMapSnapshotSource<'a> {
}

impl<'a> SnapshotSource for StorageMapSnapshotSource<'a> {
fn get(&self, key: &Rc<LedgerKey>) -> Result<Rc<LedgerEntry>, HostError> {
if let Some(Some(value)) = self.map.get::<Rc<LedgerKey>>(key, self.budget)? {
Ok(Rc::clone(value))
fn get(&self, key: &Rc<LedgerKey>) -> Result<(Rc<LedgerEntry>, Option<u32>), HostError> {
if let Some(Some((entry, expiration))) = self.map.get::<Rc<LedgerKey>>(key, self.budget)? {
Ok((Rc::clone(entry), expiration.clone()))
} else {
Err(Error::from_type_and_code(ScErrorType::Storage, ScErrorCode::InternalError).into())
}
Expand Down
Loading

0 comments on commit fc02733

Please sign in to comment.