Skip to content

Commit

Permalink
Snapshot all auths during a test not just last invokes (#1168)
Browse files Browse the repository at this point in the history
### What
Snapshot all auths during a test not just last invokes.

### Why
The test snapshot logic is using the authorization manager of the host
to get auths that have occurred. However, the authorization manager only
has the auths from the last invoke. To get all auths for the Envs
lifetime the contract invocation hook needs to be used to tell us when
each call to the host finishes so that the auths can be collected as the
test executes.

Close #1164

### Merging
Intended for merging to `main` after:
- #1167
  • Loading branch information
leighmcculloch authored Nov 18, 2023
1 parent 47105f3 commit 0a58abc
Show file tree
Hide file tree
Showing 5 changed files with 374 additions and 30 deletions.
58 changes: 39 additions & 19 deletions soroban-sdk/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ pub struct MaybeEnv {
#[cfg(any(test, feature = "testutils"))]
generators: Option<Rc<RefCell<Generators>>>,
#[cfg(any(test, feature = "testutils"))]
auth_snapshot: Option<Rc<RefCell<AuthSnapshot>>>,
#[cfg(any(test, feature = "testutils"))]
snapshot: Option<Rc<LedgerSnapshot>>,
}

Expand Down Expand Up @@ -180,6 +182,8 @@ impl MaybeEnv {
#[cfg(any(test, feature = "testutils"))]
generators: None,
#[cfg(any(test, feature = "testutils"))]
auth_snapshot: None,
#[cfg(any(test, feature = "testutils"))]
snapshot: None,
}
}
Expand Down Expand Up @@ -209,6 +213,8 @@ impl TryFrom<MaybeEnv> for Env {
#[cfg(any(test, feature = "testutils"))]
generators: value.generators.unwrap_or_default(),
#[cfg(any(test, feature = "testutils"))]
auth_snapshot: value.auth_snapshot.unwrap_or_default(),
#[cfg(any(test, feature = "testutils"))]
snapshot: value.snapshot,
})
} else {
Expand All @@ -225,6 +231,8 @@ impl From<Env> for MaybeEnv {
#[cfg(any(test, feature = "testutils"))]
generators: Some(value.generators.clone()),
#[cfg(any(test, feature = "testutils"))]
auth_snapshot: Some(value.auth_snapshot.clone()),
#[cfg(any(test, feature = "testutils"))]
snapshot: value.snapshot.clone(),
}
}
Expand All @@ -244,6 +252,8 @@ pub struct Env {
#[cfg(any(test, feature = "testutils"))]
generators: Rc<RefCell<Generators>>,
#[cfg(any(test, feature = "testutils"))]
auth_snapshot: Rc<RefCell<AuthSnapshot>>,
#[cfg(any(test, feature = "testutils"))]
snapshot: Option<Rc<LedgerSnapshot>>,
}

Expand Down Expand Up @@ -430,17 +440,19 @@ impl Env {
}

#[cfg(any(test, feature = "testutils"))]
use crate::auth;
#[cfg(any(test, feature = "testutils"))]
use crate::testutils::{
budget::Budget, Address as _, AuthSnapshot, AuthorizedInvocation, ContractFunctionSet,
EventsSnapshot, Generators, Ledger as _, MockAuth, MockAuthContract, Snapshot,
use crate::{
auth,
testutils::{
budget::Budget, Address as _, AuthSnapshot, AuthorizedInvocation, ContractFunctionSet,
EventsSnapshot, Generators, Ledger as _, MockAuth, MockAuthContract, Snapshot,
},
Bytes, BytesN,
};
#[cfg(any(test, feature = "testutils"))]
use crate::{Bytes, BytesN};
#[cfg(any(test, feature = "testutils"))]
use core::{cell::RefCell, cell::RefMut};
#[cfg(any(test, feature = "testutils"))]
use internal::ContractInvocationEvent;
#[cfg(any(test, feature = "testutils"))]
use soroban_ledger_snapshot::LedgerSnapshot;
#[cfg(any(test, feature = "testutils"))]
use std::{path::Path, rc::Rc};
Expand Down Expand Up @@ -515,10 +527,27 @@ impl Env {
.set_diagnostic_level(internal::DiagnosticLevel::Debug)
.unwrap();
env_impl.set_base_prng_seed([0; 32]).unwrap();

let auth_snapshot = Rc::new(RefCell::new(AuthSnapshot::default()));
let auth_snapshot_in_hook = auth_snapshot.clone();
env_impl
.set_top_contract_invocation_hook(Some(Rc::new(move |host, event| {
if let ContractInvocationEvent::Finish = event {
let new_auths = host
.get_authenticated_authorizations()
// If an error occurs getting the authenticated authorizations
// it means that no auth has occurred.
.unwrap_or_default();
(*auth_snapshot_in_hook).borrow_mut().0.extend(new_auths);
}
})))
.unwrap();

let env = Env {
env_impl,
generators: generators.unwrap_or_default(),
snapshot,
auth_snapshot,
};

env.ledger().set(ledger_info);
Expand Down Expand Up @@ -1216,7 +1245,7 @@ impl Env {
pub fn to_snapshot(&self) -> Snapshot {
Snapshot {
generators: (*self.generators).borrow().clone(),
auth: self.to_auth_snapshot(),
auth: (*self.auth_snapshot).borrow().clone(),
ledger: self.to_ledger_snapshot(),
events: self.to_events_snapshot(),
}
Expand Down Expand Up @@ -1288,17 +1317,6 @@ impl Env {
)
}

/// Create an auth snapshot from the Env's current state.
pub(crate) fn to_auth_snapshot(&self) -> AuthSnapshot {
AuthSnapshot(
self.env_impl
.get_authenticated_authorizations()
// If an error occurs getting the authenticated authorizations
// it means that no auth has occurred.
.unwrap_or_default(),
)
}

/// Get the budget that tracks the resources consumed for the environment.
pub fn budget(&self) -> Budget {
Budget::new(self.env_impl.budget_cloned())
Expand Down Expand Up @@ -1412,6 +1430,8 @@ impl Env {
#[cfg(any(test, feature = "testutils"))]
generators: Default::default(),
#[cfg(any(test, feature = "testutils"))]
auth_snapshot: Default::default(),
#[cfg(any(test, feature = "testutils"))]
snapshot: None,
}
}
Expand Down
20 changes: 17 additions & 3 deletions soroban-sdk/src/tests/auth/auth_10_one.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,27 @@ fn test() {
invoke: &MockAuthInvoke {
contract: &contract_id,
fn_name: "add",
args: (&a, 10, 12).into_val(&e),
args: (&a, 10, 11).into_val(&e),
sub_invokes: &[],
},
}])
.add(&a, &10, &12);
.add(&a, &10, &11);

assert_eq!(c, 22);
assert_eq!(c, 21);

let c = client
.mock_auths(&[MockAuth {
address: &a,
invoke: &MockAuthInvoke {
contract: &contract_id,
fn_name: "add",
args: (&a, 10, 13).into_val(&e),
sub_invokes: &[],
},
}])
.add(&a, &10, &13);

assert_eq!(c, 23);

println!("{:?}", e.auths());
}
Loading

0 comments on commit 0a58abc

Please sign in to comment.