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

Refactor host to support the new expiration ledger approach. #1015

Merged
merged 4 commits into from
Aug 24, 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 Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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
2 changes: 1 addition & 1 deletion soroban-env-common/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl Symbol {

impl Ord for SymbolSmall {
fn cmp(&self, other: &Self) -> Ordering {
Iterator::cmp(self.into_iter(), other.into_iter())
Iterator::cmp(self.into_iter(), *other)
}
}

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))
} else {
Err(Error::from_type_and_code(ScErrorType::Storage, ScErrorCode::InternalError).into())
}
Expand Down
Loading