Skip to content

Commit

Permalink
Add get_current_call_stack method (#574)
Browse files Browse the repository at this point in the history
* Add get_current_call_stack method

* update tests

* add example
  • Loading branch information
sisuresh authored Sep 8, 2022
1 parent 1310271 commit cd78f4b
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 3 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ members = [
"tests/vec",
"tests/import_contract",
"tests/invoke_contract",
"tests/call_stack",
"tests/udt",
"tests/contract_data",
"tests/create_contract",
Expand Down
42 changes: 39 additions & 3 deletions soroban-sdk/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub use internal::Val;
pub type EnvVal = internal::EnvVal<Env, RawVal>;
pub type EnvObj = internal::EnvVal<Env, Object>;

use crate::{deploy::Deployer, Bytes, BytesN, ContractData, Events, Ledger};
use crate::{deploy::Deployer, Bytes, BytesN, ContractData, Events, Ledger, Vec};

/// The [Env] type provides access to the environment the contract is executing
/// within.
Expand Down Expand Up @@ -194,12 +194,12 @@ impl Env {

/// Verifies an ed25519 signature.
///
/// The ed25519 siganture (`sig`) is verified as a valid signature of the
/// The ed25519 signature (`sig`) is verified as a valid signature of the
/// message (`msg`) by the ed25519 public key (`pk`).
///
/// ### Panics
///
/// Will panic if the siganture verification fails.
/// Will panic if the signature verification fails.
///
/// ### TODO
///
Expand All @@ -210,6 +210,42 @@ impl Env {
.unwrap()
}

/// Returns the contract call stack as a Vec
/// of (contractID, functionName).
///
/// ### Examples
/// ```
/// use soroban_sdk::{contractimpl, BytesN, Env, Symbol, symbol};
///
/// pub struct Contract;
///
/// #[contractimpl]
/// impl Contract {
/// pub fn hello(env: Env) {
/// let stack = env.get_current_call_stack();
/// assert_eq!(stack.len(), 1);
///
/// let outer = stack.get(0).unwrap().unwrap();
/// assert_eq!(outer.0, BytesN::from_array(&env, &[0; 32]));
/// assert_eq!(outer.1, symbol!("hello"));
/// }
/// }
/// # #[cfg(feature = "testutils")]
/// # fn main() {
/// let env = Env::default();
/// let contract_id = BytesN::from_array(&env, &[0; 32]);
/// env.register_contract(&contract_id, Contract);
/// let client = ContractClient::new(&env, &contract_id);
/// client.hello();
/// # }
/// # #[cfg(not(feature = "testutils"))]
/// # fn main() { }
/// ```
pub fn get_current_call_stack(&self) -> Vec<(BytesN<32>, Symbol)> {
let stack = internal::Env::get_current_call_stack(self);
stack.try_into_val(self).unwrap()
}

#[doc(hidden)]
pub fn log_value<V: IntoVal<Env, RawVal>>(&self, v: V) {
internal::Env::log_value(self, v.into_val(self));
Expand Down
21 changes: 21 additions & 0 deletions tests/call_stack/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "example_call_stack"
version = "0.0.4"
authors = ["Stellar Development Foundation <[email protected]>"]
license = "Apache-2.0"
edition = "2021"
publish = false
rust-version = "1.63"

[lib]
crate-type = ["cdylib", "rlib"]
doctest = false

[dependencies]
soroban-sdk = {path = "../../soroban-sdk"}

[dev-dependencies]
soroban-sdk = {path = "../../soroban-sdk", features = ["testutils"]}

[features]
testutils = ["soroban-sdk/testutils"]
65 changes: 65 additions & 0 deletions tests/call_stack/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#![no_std]
use soroban_sdk::{contractimpl, symbol, BytesN, Env};

pub struct OuterContract;

#[contractimpl]
impl OuterContract {
pub fn outer(env: Env, contract_id: BytesN<32>) {
let check_call_stack = || {
let stack = env.get_current_call_stack();
assert_eq!(stack.len(), 1);
let outer = stack.get(0).unwrap().unwrap();
assert_eq!(outer.0, BytesN::from_array(&env, &[1u8; 32]));
assert_eq!(outer.1, symbol!("outer"));
};

// Check before the inner call
check_call_stack();

let client = InnerContractClient::new(&env, &contract_id);
client.inner();

// Check after the inner call
check_call_stack();
}
}

pub struct InnerContract;

#[contractimpl]
impl InnerContract {
pub fn inner(env: Env) {
let stack = env.get_current_call_stack();
assert_eq!(stack.len(), 2);

let outer = stack.get(0).unwrap().unwrap();
assert_eq!(outer.0, BytesN::from_array(&env, &[1u8; 32]));
assert_eq!(outer.1, symbol!("outer"));

let inner = stack.get(1).unwrap().unwrap();
assert_eq!(inner.0, BytesN::from_array(&env, &[0u8; 32]));
assert_eq!(inner.1, symbol!("inner"));
}
}

#[cfg(test)]
mod test {
use soroban_sdk::{BytesN, Env};

use crate::{InnerContract, OuterContract, OuterContractClient};

#[test]
fn test() {
let e = Env::default();

let inner_contract_id = BytesN::from_array(&e, &[0; 32]);
e.register_contract(&inner_contract_id, InnerContract);

let contract_id = BytesN::from_array(&e, &[1; 32]);
e.register_contract(&contract_id, OuterContract);
let client = OuterContractClient::new(&e, &contract_id);

client.outer(&inner_contract_id);
}
}

0 comments on commit cd78f4b

Please sign in to comment.