Skip to content

Commit

Permalink
Draft of state archival simulation support
Browse files Browse the repository at this point in the history
  • Loading branch information
dmkozh authored and SirTyson committed Nov 16, 2024
1 parent a3f7fca commit 83f363c
Show file tree
Hide file tree
Showing 9 changed files with 745 additions and 209 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

7 changes: 5 additions & 2 deletions soroban-simulation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ testutils = ["soroban-env-host/testutils"]
[dependencies]
anyhow = { version = "1.0.75", features = [] }
thiserror = "1.0.40"
soroban-env-host = { workspace = true, features = ["recording_mode", "unstable-next-api"]}
soroban-env-host = { workspace = true, features = ["recording_mode", "unstable-next-api", "next"]}
stellar-xdr = { workspace = true, features = ["next"]}
static_assertions = "1.1.0"
rand = "0.8.5"


[dev-dependencies]
soroban-env-host = { workspace = true, features = ["recording_mode", "testutils", "unstable-next-api"]}
soroban-env-host = { workspace = true, features = ["recording_mode", "testutils", "unstable-next-api", "next"]}
stellar-xdr = { workspace = true, features = ["next"]}
soroban-test-wasms = { package = "soroban-test-wasms", path = "../soroban-test-wasms" }
pretty_assertions = "1.4"
tap = "1.0.1"
Expand Down
3 changes: 2 additions & 1 deletion soroban-simulation/src/network_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ fn load_configuration_setting(
let key = Rc::new(LedgerKey::ConfigSetting(LedgerKeyConfigSetting {
config_setting_id: setting_id,
}));
let (entry, _) = snapshot
let entry = snapshot
.get_including_archived(&key)?
.entry
.ok_or_else(|| anyhow!("setting {setting_id:?} is not present in the snapshot"))?;
if let LedgerEntry {
data: LedgerEntryData::ConfigSetting(cs),
Expand Down
79 changes: 48 additions & 31 deletions soroban-simulation/src/resources.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use super::snapshot_source::SnapshotSourceWithArchive;
use crate::network_config::NetworkConfig;
use crate::simulation::{SimulationAdjustmentConfig, SimulationAdjustmentFactor};
use anyhow::{anyhow, ensure, Context, Result};
use crate::snapshot_source::LedgerEntryArchivalState;
use anyhow::{anyhow, bail, ensure, Context, Result};

use soroban_env_host::xdr::ArchivalProof;
use soroban_env_host::{
e2e_invoke::{extract_rent_changes, LedgerEntryChange},
fees::{
Expand All @@ -12,12 +14,12 @@ use soroban_env_host::{
ledger_info::get_key_durability,
storage::SnapshotSource,
xdr::{
BytesM, ContractDataDurability, DecoratedSignature, Duration, ExtensionPoint, Hash,
LedgerBounds, LedgerFootprint, LedgerKey, Limits, Memo, MuxedAccount, MuxedAccountMed25519,
Operation, OperationBody, Preconditions, PreconditionsV2, ReadXdr, SequenceNumber,
Signature, SignatureHint, SignerKey, SignerKeyEd25519SignedPayload, SorobanResources,
SorobanTransactionData, TimeBounds, TimePoint, Transaction, TransactionExt,
TransactionV1Envelope, Uint256, WriteXdr,
BytesM, ContractDataDurability, DecoratedSignature, Duration, Hash, LedgerBounds,
LedgerFootprint, LedgerKey, Limits, Memo, MuxedAccount, MuxedAccountMed25519, Operation,
OperationBody, Preconditions, PreconditionsV2, ReadXdr, SequenceNumber, Signature,
SignatureHint, SignerKey, SignerKeyEd25519SignedPayload, SorobanResources,
SorobanTransactionData, SorobanTransactionDataExt, TimeBounds, TimePoint, Transaction,
TransactionExt, TransactionV1Envelope, Uint256, WriteXdr,
},
LedgerInfo, DEFAULT_XDR_RW_LIMITS,
};
Expand Down Expand Up @@ -193,7 +195,11 @@ pub(crate) fn simulate_restore_op_resources(
keys_to_restore: &[LedgerKey],
snapshot_source: &impl SnapshotSourceWithArchive,
ledger_info: &LedgerInfo,
) -> Result<(SorobanResources, Vec<LedgerEntryRentChange>)> {
) -> Result<(
SorobanResources,
Vec<LedgerEntryRentChange>,
Option<ArchivalProof>,
)> {
let restored_live_until_ledger = ledger_info
.min_live_until_ledger_checked(ContractDataDurability::Persistent)
.ok_or_else(|| {
Expand All @@ -202,36 +208,42 @@ pub(crate) fn simulate_restore_op_resources(
let mut restored_bytes = 0_u32;
let mut rent_changes: Vec<LedgerEntryRentChange> = Vec::with_capacity(keys_to_restore.len());
let mut restored_keys = Vec::<LedgerKey>::with_capacity(keys_to_restore.len());
let mut restored_keys_needing_proof =
Vec::<Rc<LedgerKey>>::with_capacity(keys_to_restore.len());

for key in keys_to_restore {
let durability = get_key_durability(key);
ensure!(
durability == Some(ContractDataDurability::Persistent),
"Can't restore a ledger entry with key: {key:?}. Only persistent ledger entries with TTL can be restored."
);
let entry_with_live_until = snapshot_source
.get_including_archived(&Rc::new(key.clone()))?
.ok_or_else(|| anyhow!("Missing entry to restore for key {key:?}"))?;
let (entry, live_until) = entry_with_live_until;

let current_live_until_ledger = live_until.ok_or_else(|| {
anyhow!("Internal error: missing TTL for ledger key that must have TTL: `{key:?}`")
})?;

if current_live_until_ledger >= ledger_info.sequence_number {
continue;
let rc_key = Rc::new(key.clone());
let entry_state = snapshot_source.get_including_archived(&rc_key)?;
match &entry_state.state {
LedgerEntryArchivalState::Archived(need_proof) => {
if *need_proof {
restored_keys_needing_proof.push(rc_key.clone());
}
restored_keys.push(key.clone());
}
_ => {
continue;
}
}
restored_keys.push(key.clone());

let entry_size: u32 = entry.to_xdr(DEFAULT_XDR_RW_LIMITS)?.len().try_into()?;
restored_bytes = restored_bytes.saturating_add(entry_size);
rent_changes.push(LedgerEntryRentChange {
is_persistent: true,
old_size_bytes: 0,
new_size_bytes: entry_size,
old_live_until_ledger: 0,
new_live_until_ledger: restored_live_until_ledger,
});
if let Some(entry) = &entry_state.entry {
let entry_size: u32 = entry.to_xdr(DEFAULT_XDR_RW_LIMITS)?.len().try_into()?;
restored_bytes = restored_bytes.saturating_add(entry_size);
rent_changes.push(LedgerEntryRentChange {
is_persistent: true,
old_size_bytes: 0,
new_size_bytes: entry_size,
old_live_until_ledger: 0,
new_live_until_ledger: restored_live_until_ledger,
});
} else {
bail!("missing entry to be restored for key '{key:?}', is the archive incomplete?");
}
}
restored_keys.sort();
let resources = SorobanResources {
Expand All @@ -243,7 +255,12 @@ pub(crate) fn simulate_restore_op_resources(
read_bytes: restored_bytes,
write_bytes: restored_bytes,
};
Ok((resources, rent_changes))
let archival_proof = if !restored_keys_needing_proof.is_empty() {
Some(snapshot_source.generate_restoration_proof(restored_keys_needing_proof.as_slice())?)
} else {
None
};
Ok((resources, rent_changes, archival_proof))
}

fn estimate_max_transaction_size_for_operation(
Expand Down Expand Up @@ -299,7 +316,7 @@ fn estimate_max_transaction_size_for_operation(
write_bytes: 0,
},
resource_fee: 0,
ext: ExtensionPoint::V0,
ext: SorobanTransactionDataExt::V0,
}),
},
signatures: signatures.try_into()?,
Expand Down
34 changes: 24 additions & 10 deletions soroban-simulation/src/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ use soroban_env_host::{
e2e_invoke::LedgerEntryChange,
storage::SnapshotSource,
xdr::{
AccountId, ContractEvent, DiagnosticEvent, HostFunction, InvokeHostFunctionOp, LedgerKey,
OperationBody, ScVal, SorobanAuthorizationEntry, SorobanResources, SorobanTransactionData,
AccountId, ArchivalProof, ContractEvent, DiagnosticEvent, ExtendFootprintTtlOp,
ExtensionPoint, HostFunction, InvokeHostFunctionOp, LedgerEntry, LedgerKey, OperationBody,
ReadXdr, RestoreFootprintOp, ScVal, SorobanAuthorizationEntry, SorobanResources,
SorobanTransactionData, SorobanTransactionDataExt,
},
xdr::{ExtendFootprintTtlOp, ExtensionPoint, LedgerEntry, ReadXdr, RestoreFootprintOp},
HostError, LedgerInfo, DEFAULT_XDR_RW_LIMITS,
};
use std::rc::Rc;
Expand Down Expand Up @@ -116,7 +117,7 @@ pub struct RestoreOpSimulationResult {
/// for failed invocations. It should only fail if ledger is
/// mis-configured (e.g. when computed fees cause overflows).
#[allow(clippy::too_many_arguments)]
pub fn simulate_invoke_host_function_op(
pub fn simulate_invoke_host_function_op<F>(
snapshot_source: Rc<dyn SnapshotSource>,
network_config: &NetworkConfig,
adjustment_config: &SimulationAdjustmentConfig,
Expand All @@ -126,7 +127,11 @@ pub fn simulate_invoke_host_function_op(
source_account: &AccountId,
base_prng_seed: [u8; 32],
enable_diagnostics: bool,
) -> Result<InvokeHostFunctionSimulationResult> {
generate_new_entry_proof: F,
) -> Result<InvokeHostFunctionSimulationResult>
where
F: FnOnce() -> Result<Option<ArchivalProof>>,
{
let snapshot_source = Rc::new(SimulationSnapshotSource::new_from_rc(snapshot_source));
let budget = network_config.create_budget()?;
let mut diagnostic_events = vec![];
Expand Down Expand Up @@ -194,7 +199,11 @@ pub fn simulate_invoke_host_function_op(
&rent_changes,
adjustment_config,
);
simulation_result.transaction_data = Some(create_transaction_data(resources, resource_fee));
simulation_result.transaction_data = Some(create_transaction_data(
resources,
resource_fee,
generate_new_entry_proof()?,
));

Ok(simulation_result)
}
Expand Down Expand Up @@ -243,7 +252,7 @@ pub fn simulate_extend_ttl_op(
adjustment_config,
);
Ok(ExtendTtlOpSimulationResult {
transaction_data: create_transaction_data(resources, resource_fee),
transaction_data: create_transaction_data(resources, resource_fee, None),
})
}

Expand Down Expand Up @@ -271,7 +280,7 @@ pub fn simulate_restore_op(
keys_to_restore: &[LedgerKey],
) -> Result<RestoreOpSimulationResult> {
let snapshot_source = SimulationSnapshotSourceWithArchive::new(snapshot_source);
let (mut resources, rent_changes) =
let (mut resources, rent_changes, archival_proof) =
simulate_restore_op_resources(keys_to_restore, &snapshot_source, ledger_info)?;
let operation = OperationBody::RestoreFootprint(RestoreFootprintOp {
ext: ExtensionPoint::V0,
Expand All @@ -286,7 +295,7 @@ pub fn simulate_restore_op(
adjustment_config,
);
Ok(RestoreOpSimulationResult {
transaction_data: create_transaction_data(resources, resource_fee),
transaction_data: create_transaction_data(resources, resource_fee, archival_proof),
})
}

Expand Down Expand Up @@ -333,11 +342,16 @@ impl SimulationAdjustmentConfig {
fn create_transaction_data(
resources: SorobanResources,
resource_fee: i64,
new_entries_proof: Option<ArchivalProof>,
) -> SorobanTransactionData {
SorobanTransactionData {
resources,
resource_fee,
ext: ExtensionPoint::V0,
ext: if let Some(proof) = new_entries_proof {
SorobanTransactionDataExt::V1(vec![proof].try_into().unwrap())
} else {
SorobanTransactionDataExt::V0
},
}
}

Expand Down
Loading

0 comments on commit 83f363c

Please sign in to comment.