Skip to content

Commit

Permalink
Rollback tests (#1177)
Browse files Browse the repository at this point in the history
### What

Resolves #1150,
#1151

Resolves the "Test that after a call or a try_call that does a transfer
and then fails, nothing was spent" test in
#1166.
  • Loading branch information
sisuresh committed Nov 4, 2023
1 parent c46f3f5 commit e2f9c1d
Show file tree
Hide file tree
Showing 41 changed files with 121 additions and 5 deletions.
89 changes: 86 additions & 3 deletions soroban-env-host/src/test/stellar_asset_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ use crate::{
use ed25519_dalek::SigningKey;
use soroban_env_common::{
xdr::{
self, AccountFlags, ContractExecutable, InvokeContractArgs, ScAddress, ScContractInstance,
ScSymbol, ScVal, SorobanAuthorizedFunction, SorobanAuthorizedInvocation,
self, AccountFlags, ContractEventType, ContractExecutable, InvokeContractArgs, ScAddress,
ScContractInstance, ScSymbol, ScVal, SorobanAuthorizedFunction,
SorobanAuthorizedInvocation,
},
xdr::{
AccountId, AlphaNum12, AlphaNum4, Asset, AssetCode12, AssetCode4, Hash, LedgerEntryData,
Expand All @@ -33,6 +34,7 @@ use soroban_env_common::{
EnvBase, Val,
};
use soroban_env_common::{Env, Symbol, TryFromVal, TryIntoVal};
use soroban_test_wasms::{ERR, INVOKE_CONTRACT};
use stellar_strkey::ed25519;

use crate::builtin_contracts::base_types::BytesN;
Expand Down Expand Up @@ -421,7 +423,10 @@ fn test_asset_init(asset_code: &[u8]) {
assert_eq!(contract.decimals().unwrap(), 7);
let name = contract.name().unwrap().to_string();

let mut expected = String::from_utf8(asset_code.to_vec()).unwrap();
let mut expected = String::from_utf8(asset_code.to_vec())
.unwrap()
.trim_matches(char::from(0))
.to_string();
expected.push(':');
let k = ed25519::PublicKey(test.issuer_key.verifying_key().to_bytes());
expected.push_str(k.to_string().as_str());
Expand Down Expand Up @@ -449,6 +454,16 @@ fn test_asset12_smart_init() {
]);
}

#[test]
fn test_asset4_smart_leading_zero_init() {
test_asset_init(&[b'z', b'a', 0, 0]);
}

#[test]
fn test_asset12_smart_leading_zero_init() {
test_asset_init(&[65, 76, b'a', b'b', b'a', b'b', b'c', b'a', b'b', b'a', 0, 0]);
}

#[test]
fn test_zero_amounts() {
let test = StellarAssetContractTest::setup();
Expand Down Expand Up @@ -3007,3 +3022,71 @@ fn test_recording_auth_for_stellar_asset_contract() {
)]
);
}

#[test]
fn verify_nested_try_call_rollback() -> Result<(), HostError> {
// This test calls "invoke" in the ivocation contract, which then dispatches a call
// to "fail_after_updates". "fail_after_updates" emits an event, saves data, and does a
// SAC token transfer before emitting an error.

let test = StellarAssetContractTest::setup();

let invoke_id_obj = test.host.register_test_contract_wasm(INVOKE_CONTRACT);
let err_id_obj = test.host.register_test_contract_wasm(ERR);
let err_address = Address::try_from_val(&test.host, &err_id_obj)?;

let admin = TestSigner::account(&test.issuer_key);
let contract = test.default_stellar_asset_contract();

contract
.mint(&admin, err_address.clone(), 100_000_000)
.unwrap();

test.host.call(
invoke_id_obj,
Symbol::try_from_small_str("invoke")?,
host_vec![
&test.host,
err_id_obj,
Symbol::try_from_val(&test.host, &"fail_after_updates").unwrap(),
contract.address.as_object()
]
.into(),
)?;

assert_eq!(contract.balance(err_address.clone()).unwrap(), 100_000_000);
assert_eq!(contract.balance(contract.address.clone()).unwrap(), 0);

assert_eq!(
bool::try_from_val(
&test.host,
&test.host.call(
err_id_obj,
Symbol::try_from_val(&test.host, &"storage_updated")?,
host_vec![&test.host].into(),
)?
)?,
false
);

let events = test.host.get_events()?.0;

// Make sure the event emitted in "fail_after_updates" is marked as failed
assert!(
events
.iter()
.find(|e| {
if e.event.type_ == ContractEventType::Contract && e.event.contract_id.is_some() {
let address = ScAddress::Contract(e.event.contract_id.clone().unwrap());
let id = test.host.add_host_object(address).unwrap();
test.host.obj_cmp(err_id_obj.to_val(), id.to_val()).unwrap() == 0
} else {
false
}
})
.unwrap()
.failed_call
);

Ok(())
}
26 changes: 25 additions & 1 deletion soroban-test-wasms/wasm-workspace/err/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![no_std]
use soroban_sdk::{contract, contractimpl, contracterror, Val, Error};
use soroban_sdk::{contract, contractimpl, contracterror, Val, Error, Env, Symbol, Address, symbol_short, token};

#[contract]
pub struct Contract;
Expand Down Expand Up @@ -47,4 +47,28 @@ impl Contract {
Error::from_contract_error(12345).into()
}

// This function is used in a try_call invocation test to make sure
// state is rolled back on failure.
pub fn fail_after_updates(env: Env, token: Address) -> Result<(), Error> {
env.events()
.publish((Symbol::new(&env, &"fail_after_updates"),), ());

env.storage().instance().set(&symbol_short!("key"), &symbol_short!("val"));
env.storage().persistent().set(&symbol_short!("key"), &symbol_short!("val"));
env.storage().temporary().set(&symbol_short!("key"), &symbol_short!("val"));

let client = token::Client::new(&env, &token);
let contract_address = env.current_contract_address();
// Transfer to the token address to make the test easier.
client.transfer(&contract_address, &token, &10);

let e: Error = Error::from_contract_error(12345).into();
Err(e)
}

pub fn storage_updated(e: Env) -> bool {
e.storage().instance().has(&symbol_short!("key")) ||
e.storage().persistent().has(&symbol_short!("key")) ||
e.storage().temporary().has(&symbol_short!("key"))
}
}
11 changes: 10 additions & 1 deletion soroban-test-wasms/wasm-workspace/invoke_contract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![no_std]
use soroban_sdk::{contract, contractimpl, vec, Address, Env, IntoVal, symbol_short};
use soroban_sdk::{contract, contractimpl, vec, Address, Env, IntoVal, Symbol, symbol_short, Error};

#[contract]
pub struct Contract;
Expand All @@ -20,4 +20,13 @@ impl Contract {
vec![&env, x.into_val(&env), y.into_val(&env)],
)
}

// This is used through a single test case to test various rollback scenarios
pub fn invoke(env: Env, contract_id: Address, function_name: Symbol, token: Address) {
assert!(env.try_invoke_contract::<(), Error>(
&contract_id,
&function_name,
vec![&env, token.into_val(&env)],
).is_err());
}
}
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/auth_test_contract.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/example_add_f32.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/example_add_i32.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/example_alloc.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/example_complex.wasm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/example_err.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/example_fannkuch.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/example_fib.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/example_hostile.wasm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/curr/example_vec.wasm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/auth_test_contract.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/example_add_f32.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/example_add_i32.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/example_alloc.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/example_complex.wasm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/example_err.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/example_fannkuch.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/example_fib.wasm
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/example_hostile.wasm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified soroban-test-wasms/wasm-workspace/opt/next/example_vec.wasm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit e2f9c1d

Please sign in to comment.