use anyhow::{Context, Result};
use miden_client::account::AccountStorageMode;
use miden_client::auth::RPO_FALCON_SCHEME_ID;
use miden_client::testing::common::{execute_tx_and_sync, insert_new_wallet, wait_for_blocks};
use miden_client::transaction::{OutputNote, TransactionRequestBuilder};
use miden_client::{Felt, Word, ZERO};
use super::fpi::{FPI_STORAGE_VALUE, MAP_KEY, MAP_SLOT_NAME, deploy_foreign_account};
use super::network_transaction::{
COUNTER_SLOT_NAME,
deploy_counter_contract,
get_network_note_with_script,
};
use crate::tests::config::ClientConfig;
pub async fn test_network_fpi(client_config: ClientConfig) -> Result<()> {
let (mut client, keystore) = client_config.clone().into_client().await?;
client.sync_state().await?;
let (foreign_account, proc_root) = deploy_foreign_account(
&mut client,
&keystore,
AccountStorageMode::Public,
format!(
r#"
const MAP_STORAGE_SLOT = word("{MAP_SLOT_NAME}")
#! Inputs: [pad(16)]
#! Outputs: [VALUE, pad(12)]
pub proc get_fpi_map_item
# map key
push.{map_key}
# => [KEY, pad(16)]
# item slot
push.MAP_STORAGE_SLOT[0..2]
# => [slot_id_prefix, slot_id_suffix, KEY, pad(16)]
exec.::miden::protocol::active_account::get_map_item
# => [VALUE, pad(16)]
# truncate the stack
swapw dropw
# => [VALUE, pad(12)]
end
"#,
map_key = Word::from(MAP_KEY)
),
RPO_FALCON_SCHEME_ID,
)
.await?;
let foreign_account_id = foreign_account.id();
client.sync_state().await?;
let (mut client2, keystore2) =
ClientConfig::new(client_config.rpc_endpoint, client_config.rpc_timeout_ms)
.into_client()
.await?;
client2.sync_state().await?;
let target_network_account =
deploy_counter_contract(&mut client2, AccountStorageMode::Network).await?;
client2.sync_state().await?;
let (sender_account, ..) = insert_new_wallet(
&mut client2,
AccountStorageMode::Private,
&keystore2,
RPO_FALCON_SCHEME_ID,
)
.await?;
let network_fpi_note_script = format!(
"
use miden::protocol::tx
use external_contract::counter_contract
use miden::core::sys
begin
# push the hash of the `get_fpi_map_item` account procedure
push.{proc_root}
# push the foreign account id
push.{account_id_suffix} push.{account_id_prefix}
# => [foreign_id_prefix, foreign_id_suffix, FOREIGN_PROC_ROOT, pad(16)]
exec.tx::execute_foreign_procedure
push.{fpi_value} assert_eqw
call.counter_contract::increment_count
exec.sys::truncate_stack
end
",
fpi_value = Word::from(FPI_STORAGE_VALUE),
account_id_prefix = foreign_account_id.prefix().as_u64(),
account_id_suffix = foreign_account_id.suffix(),
);
let network_note = get_network_note_with_script(
sender_account.id(),
target_network_account.id(),
&network_fpi_note_script,
&mut client2.rng(),
)?;
let tx_request = TransactionRequestBuilder::new()
.own_output_notes([OutputNote::Full(network_note)])
.build()?;
execute_tx_and_sync(&mut client2, sender_account.id(), tx_request).await?;
wait_for_blocks(&mut client2, 2).await;
let updated_network_account = client2
.test_rpc_api()
.get_account_details(target_network_account.id())
.await?
.account()
.cloned()
.with_context(|| "account details not available")?;
assert_eq!(
updated_network_account.storage().get_item(&COUNTER_SLOT_NAME)?,
Word::from([ZERO, ZERO, ZERO, Felt::new(2)])
);
Ok(())
}