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

Allow passing the setting for non-root auth to the simulation. #1503

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
61 changes: 54 additions & 7 deletions soroban-env-host/src/e2e_invoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,25 @@ fn clear_signature(auth_entry: &mut SorobanAuthorizationEntry) {
}
}

#[cfg(any(test, feature = "recording_mode"))]
#[cfg(not(feature = "unstable-next-api"))]
/// Defines the authorization mode for the `invoke_host_function_in_recording_mode`.
///
/// When `None`, recording authorization with disabled non-root authorization will be used.
/// When `Some()`, enforcing auth will be used with the provided entries.
pub type RecordingInvocationAuthMode = Option<Vec<SorobanAuthorizationEntry>>;

#[cfg(all(any(test, feature = "recording_mode"), feature = "unstable-next-api"))]
/// Defines the authorization mode for the `invoke_host_function_in_recording_mode`.
pub enum RecordingInvocationAuthMode {
/// Use enforcing auth and pass the signed authorization entries to be used.
Enforcing(Vec<SorobanAuthorizationEntry>),
/// Use recording auth and determine whether non-root authorization is
/// disabled (i.e. non-root auth is not allowed when `true` is passed to
/// the enum).
Recording(bool),
}

/// Invokes a host function within a fresh host instance in 'recording' mode.
///
/// The purpose of recording mode is to measure the resources necessary for
Expand All @@ -503,10 +522,11 @@ fn clear_signature(auth_entry: &mut SorobanAuthorizationEntry) {
/// - Footprint - this is based on the ledger entries accessed.
/// - Read/write bytes - this is based on the sizes of ledger entries read
/// from the provided `ledger_snapshot`
/// - Authorization payloads - when the input `auth_entries` is `None`, Host
/// - Authorization mode - when the input `auth_mode` is `None`, Host
/// switches to recording auth mode and fills the recorded data in the output.
/// When `auth_entries` is not `None`, the authorization is performed in
/// enforcing mode and `auth_entries` are passed through to the output.
/// When `auth_mode` is not `None`, the authorization is performed in
/// enforcing mode and entries from `auth_mode` are passed through to the
/// output.
/// - Instructions - this simply measures the instructions measured by the
/// provided `budget`. While this function makes the best effort to emulate
/// the work performed by `invoke_host_function`, the measured value might
Expand All @@ -532,26 +552,40 @@ pub fn invoke_host_function_in_recording_mode(
enable_diagnostics: bool,
host_fn: &HostFunction,
source_account: &AccountId,
auth_entries: Option<Vec<SorobanAuthorizationEntry>>,
auth_mode: RecordingInvocationAuthMode,
ledger_info: LedgerInfo,
ledger_snapshot: Rc<dyn SnapshotSource>,
base_prng_seed: [u8; 32],
diagnostic_events: &mut Vec<DiagnosticEvent>,
) -> Result<InvokeHostFunctionRecordingModeResult, HostError> {
let storage = Storage::with_recording_footprint(ledger_snapshot.clone());
let host = Host::with_storage_and_budget(storage, budget.clone());
let is_recording_auth = auth_entries.is_none();
#[cfg(not(feature = "unstable-next-api"))]
let is_recording_auth = auth_mode.is_none();
#[cfg(feature = "unstable-next-api")]
let is_recording_auth = matches!(auth_mode, RecordingInvocationAuthMode::Recording(_));
let ledger_seq = ledger_info.sequence_number;
let host_function = host.xdr_roundtrip(host_fn)?;
let source_account: AccountId = host.xdr_roundtrip(source_account)?;
host.set_source_account(source_account)?;
host.set_ledger_info(ledger_info)?;
host.set_base_prng_seed(base_prng_seed)?;
if let Some(auth_entries) = &auth_entries {

#[cfg(not(feature = "unstable-next-api"))]
if let Some(auth_entries) = &auth_mode {
host.set_authorization_entries(auth_entries.clone())?;
} else {
host.switch_to_recording_auth(true)?;
}
#[cfg(feature = "unstable-next-api")]
match &auth_mode {
RecordingInvocationAuthMode::Enforcing(auth_entries) => {
host.set_authorization_entries(auth_entries.clone())?;
}
RecordingInvocationAuthMode::Recording(disable_non_root_auth) => {
host.switch_to_recording_auth(*disable_non_root_auth)?;
}
}

if enable_diagnostics {
host.set_diagnostic_level(DiagnosticLevel::Debug)?;
Expand All @@ -564,7 +598,9 @@ pub fn invoke_host_function_in_recording_mode(
contract_events_and_return_value_size = contract_events_and_return_value_size
.saturating_add(encoded_result_sc_val.len() as u32);
}
let mut output_auth = if let Some(auth_entries) = auth_entries {

#[cfg(not(feature = "unstable-next-api"))]
let mut output_auth = if let Some(auth_entries) = auth_mode {
auth_entries
} else {
let recorded_auth = host.get_recorded_auth_payloads()?;
Expand All @@ -573,6 +609,17 @@ pub fn invoke_host_function_in_recording_mode(
.map(|a| a.into_auth_entry_with_emulated_signature())
.collect::<Result<Vec<SorobanAuthorizationEntry>, HostError>>()?
};
#[cfg(feature = "unstable-next-api")]
let mut output_auth = if let RecordingInvocationAuthMode::Enforcing(auth_entries) = auth_mode {
auth_entries
} else {
let recorded_auth = host.get_recorded_auth_payloads()?;
recorded_auth
.into_iter()
.map(|a| a.into_auth_entry_with_emulated_signature())
.collect::<Result<Vec<SorobanAuthorizationEntry>, HostError>>()?
};

let encoded_auth_entries = output_auth
.iter()
.map(|e| host.to_xdr_non_metered(e))
Expand Down
51 changes: 37 additions & 14 deletions soroban-env-host/src/test/e2e_tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::builtin_contracts::testutils::AccountContractSigner;
use crate::e2e_invoke::RecordingInvocationAuthMode;
use crate::e2e_testutils::{account_entry, bytes_sc_val, upload_wasm_host_fn};
use crate::testutils::simple_account_sign_fn;
use crate::{
Expand Down Expand Up @@ -191,6 +192,28 @@ impl LedgerEntryChangeHelper {
}
}

// NB: this is a temporary helper function that we should remove and embed
// RecordingInvocationAuthMode into code during the `unstable-next-api` cleanup
// when switching to v23.
fn recording_auth_mode() -> RecordingInvocationAuthMode {
#[cfg(not(feature = "unstable-next-api"))]
return None;
#[cfg(feature = "unstable-next-api")]
return RecordingInvocationAuthMode::Recording(true);
}

// NB: this is a temporary helper function that we should remove and embed
// RecordingInvocationAuthMode into code during the `unstable-next-api` cleanup
// when switching to v23.
fn enforcing_auth_mode(
auth_entries: Vec<SorobanAuthorizationEntry>,
) -> RecordingInvocationAuthMode {
#[cfg(not(feature = "unstable-next-api"))]
return Some(auth_entries);
#[cfg(feature = "unstable-next-api")]
return RecordingInvocationAuthMode::Enforcing(auth_entries);
}

struct InvokeHostFunctionHelperResult {
invoke_result: Result<ScVal, HostError>,
ledger_changes: Vec<LedgerEntryChangeHelper>,
Expand Down Expand Up @@ -294,7 +317,7 @@ fn invoke_host_function_recording_helper(
enable_diagnostics: bool,
host_fn: &HostFunction,
source_account: &AccountId,
auth_entries: Option<Vec<SorobanAuthorizationEntry>>,
auth_mode: RecordingInvocationAuthMode,
ledger_info: &LedgerInfo,
ledger_entries_with_ttl: Vec<(LedgerEntry, Option<u32>)>,
prng_seed: &[u8; 32],
Expand All @@ -311,7 +334,7 @@ fn invoke_host_function_recording_helper(
enable_diagnostics,
host_fn,
source_account,
auth_entries,
auth_mode,
ledger_info.clone(),
snapshot,
*prng_seed,
Expand Down Expand Up @@ -342,7 +365,7 @@ fn invoke_host_function_using_simulation_with_signers(
enable_diagnostics,
host_fn,
source_account,
None,
recording_auth_mode(),
ledger_info,
ledger_entries_with_ttl.clone(),
prng_seed,
Expand All @@ -360,7 +383,7 @@ fn invoke_host_function_using_simulation_with_signers(
enable_diagnostics,
host_fn,
source_account,
Some(signed_auth.clone()),
enforcing_auth_mode(signed_auth.clone()),
ledger_info,
ledger_entries_with_ttl.clone(),
prng_seed,
Expand Down Expand Up @@ -557,7 +580,7 @@ fn test_run_out_of_budget_before_calling_host_in_recording_mode() {
true,
&upload_wasm_host_fn(ADD_I32),
&get_account_id([0; 32]),
None,
recording_auth_mode(),
&default_ledger_info(),
vec![],
&prng_seed(),
Expand Down Expand Up @@ -646,7 +669,7 @@ fn test_wasm_upload_success_in_recording_mode() {
false,
&upload_wasm_host_fn(ADD_I32),
&get_account_id([123; 32]),
None,
recording_auth_mode(),
&ledger_info,
vec![],
&prng_seed(),
Expand Down Expand Up @@ -699,7 +722,7 @@ fn test_wasm_upload_failure_in_recording_mode() {
true,
&upload_wasm_host_fn(&[0_u8; 1000]),
&get_account_id([123; 32]),
None,
recording_auth_mode(),
&ledger_info,
vec![],
&prng_seed(),
Expand Down Expand Up @@ -737,7 +760,7 @@ fn test_unsupported_wasm_upload_failure_in_recording_mode() {
true,
&upload_wasm_host_fn(ADD_F32),
&get_account_id([123; 32]),
None,
recording_auth_mode(),
&ledger_info,
vec![],
&prng_seed(),
Expand Down Expand Up @@ -1149,7 +1172,7 @@ fn test_create_contract_success_in_recording_mode() {
true,
&cd.host_fn,
&cd.deployer,
None,
recording_auth_mode(),
&ledger_info,
vec![(
cd.wasm_entry.clone(),
Expand Down Expand Up @@ -1235,7 +1258,7 @@ fn test_create_contract_success_in_recording_mode_with_custom_account() {
true,
&cd.host_fn,
&cd.deployer,
None,
recording_auth_mode(),
&ledger_info,
vec![
(
Expand Down Expand Up @@ -1351,7 +1374,7 @@ fn test_create_contract_success_in_recording_mode_with_enforced_auth() {
true,
&cd.host_fn,
&cd.deployer,
Some(vec![cd.auth_entry.clone()]),
enforcing_auth_mode(vec![cd.auth_entry.clone()]),
&ledger_info,
vec![(
cd.wasm_entry.clone(),
Expand Down Expand Up @@ -1767,7 +1790,7 @@ fn test_invoke_contract_with_storage_ops_success_in_recording_mode() {
true,
&host_fn,
&cd.deployer,
None,
recording_auth_mode(),
&ledger_info,
vec![
(
Expand Down Expand Up @@ -1842,7 +1865,7 @@ fn test_invoke_contract_with_storage_ops_success_in_recording_mode() {
true,
&extend_host_fn,
&cd.deployer,
None,
recording_auth_mode(),
&ledger_info,
vec![
(
Expand Down Expand Up @@ -1945,7 +1968,7 @@ fn test_invoke_contract_with_storage_ops_success_using_simulation() {
true,
&extend_host_fn,
&cd.deployer,
None,
recording_auth_mode(),
&ledger_info,
vec![
(
Expand Down
5 changes: 3 additions & 2 deletions soroban-simulation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ publish = true

[features]
testutils = ["soroban-env-host/testutils"]
unstable-next-api = ["soroban-env-host/unstable-next-api"]

[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"]}
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"]}
soroban-test-wasms = { package = "soroban-test-wasms", path = "../soroban-test-wasms" }
pretty_assertions = "1.4"
tap = "1.0.1"
Expand Down
13 changes: 7 additions & 6 deletions soroban-simulation/src/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::snapshot_source::{
use anyhow::Result;
use soroban_env_host::{
e2e_invoke::invoke_host_function_in_recording_mode,
e2e_invoke::LedgerEntryChange,
e2e_invoke::{LedgerEntryChange, RecordingInvocationAuthMode},
storage::SnapshotSource,
xdr::{
AccountId, ContractEvent, DiagnosticEvent, HostFunction, InvokeHostFunctionOp, LedgerKey,
Expand Down Expand Up @@ -100,9 +100,10 @@ pub struct RestoreOpSimulationResult {
/// relevant payload parts.
///
/// The operation is defined by the host function itself (`host_fn`)
/// and optionally signed `auth_entries`. In case if `auth_entries` are
/// omitted, the simulation will use recording authorization mode and
/// return non-signed recorded authorization entries.
/// and `auth_mode`. In case if `auth_mode` is `None`, the simulation will
/// use recording authorization mode and return non-signed recorded
/// authorization entries. Otherwise, the signed entries will be used for
/// authorization and authentication enforcement.
///
/// The rest of parameters define the ledger state (`snapshot_source`,
/// `network_config`, `ledger_info`), simulation adjustment
Expand All @@ -122,7 +123,7 @@ pub fn simulate_invoke_host_function_op(
adjustment_config: &SimulationAdjustmentConfig,
ledger_info: &LedgerInfo,
host_fn: HostFunction,
auth_entries: Option<Vec<SorobanAuthorizationEntry>>,
auth_mode: RecordingInvocationAuthMode,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this not need to be behind the unstable-next-api flag?

source_account: &AccountId,
base_prng_seed: [u8; 32],
enable_diagnostics: bool,
Expand All @@ -135,7 +136,7 @@ pub fn simulate_invoke_host_function_op(
enable_diagnostics,
&host_fn,
source_account,
auth_entries,
auth_mode,
ledger_info.clone(),
snapshot_source.clone(),
base_prng_seed,
Expand Down
Loading
Loading