Skip to content

Commit

Permalink
add madara update state test
Browse files Browse the repository at this point in the history
  • Loading branch information
byteZorvin committed Sep 27, 2024
1 parent 4aa76ba commit 003b3ae
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 58 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

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

11 changes: 8 additions & 3 deletions crates/settlement-clients/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use mockall::{automock, predicate::*};
use alloy::providers::ProviderBuilder;
use conversion::{get_input_data_for_eip_4844, prepare_sidecar};
#[cfg(not(feature = "testing"))]
use settlement_client_interface::{SettlementClient, SettlementConfig, SettlementVerificationStatus};
use settlement_client_interface::{SettlementClient, SettlementVerificationStatus};
#[cfg(feature = "testing")]
use settlement_client_interface::{SettlementClient, SettlementVerificationStatus};
#[cfg(feature = "testing")]
Expand Down Expand Up @@ -164,11 +164,16 @@ impl SettlementClient for EthereumSettlementClient {
&self,
program_output: Vec<[u8; 32]>,
onchain_data_hash: [u8; 32],
onchain_data_size: usize,
onchain_data_size: [u128; 2],
) -> Result<String> {
let program_output: Vec<U256> = vec_u8_32_to_vec_u256(program_output.as_slice())?;
let onchain_data_hash: U256 = slice_u8_to_u256(&onchain_data_hash)?;
let onchain_data_size: U256 = onchain_data_size.try_into()?;
let mut bytes = [0u8; 32];

bytes[0..16].copy_from_slice(&onchain_data_size[0].to_le_bytes());
bytes[16..32].copy_from_slice(&onchain_data_size[1].to_le_bytes());

let onchain_data_size = U256::from_le_bytes(bytes);
let tx_receipt =
self.core_contract_client.update_state(program_output, onchain_data_hash, onchain_data_size).await?;
Ok(format!("0x{:x}", tx_receipt.transaction_hash))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub trait SettlementClient: Send + Sync {
&self,
program_output: Vec<[u8; 32]>,
onchain_data_hash: [u8; 32],
onchain_data_size: usize,
onchain_data_size: [u128; 2],
) -> Result<String>;

/// Should be used to update state on contract and publish the blob on ethereum.
Expand Down
8 changes: 4 additions & 4 deletions crates/settlement-clients/starknet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use color_eyre::Result;
use lazy_static::lazy_static;
use mockall::{automock, predicate::*};
use starknet::accounts::ConnectedAccount;
use starknet::core::types::TransactionExecutionStatus;
use starknet::core::types::{TransactionExecutionStatus, U256};
use starknet::providers::Provider;
use starknet::{
accounts::{ExecutionEncoding, SingleOwnerAccount},
Expand Down Expand Up @@ -117,15 +117,15 @@ impl SettlementClient for StarknetSettlementClient {
&self,
program_output: Vec<[u8; 32]>,
onchain_data_hash: [u8; 32],
onchain_data_size: usize,
onchain_data_size: [u128; 2],
) -> Result<String> {
let program_output = slice_slice_u8_to_vec_field(program_output.as_slice());
let onchain_data_hash = slice_u8_to_field(&onchain_data_hash);
let onchain_data_size = Felt::from(onchain_data_size);
let core_contract: &CoreContract = self.starknet_core_contract_client.as_ref();
let onchain_data_size = U256::from_words(onchain_data_size[0], onchain_data_size[1]);
let invoke_result = core_contract.update_state(program_output, onchain_data_hash, onchain_data_size).await?;

Ok(format!("0x{:x}", invoke_result.transaction_hash))
Ok(invoke_result.transaction_hash.to_hex_string())
}

/// Should verify the inclusion of a tx in the settlement layer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ pub trait IPiltover<TContractState> {
onchain_data_hash: felt252,
onchain_data_size: u256
);

fn get_is_updated(self: @TContractState, onchain_data_hash: felt252) -> bool;
}

#[starknet::contract]
mod Piltover {
use starknet::storage::Map;
#[storage]
struct Storage {
balance: felt252,
is_updated: Map<felt252, bool>,
}

#[abi(embed_v0)]
Expand All @@ -22,6 +25,12 @@ mod Piltover {
program_output: Span<felt252>,
onchain_data_hash: felt252,
onchain_data_size: u256
) {}
) {
self.is_updated.write(onchain_data_hash, true);
}

fn get_is_updated(self: @ContractState, onchain_data_hash: felt252) -> bool {
self.is_updated.read(onchain_data_hash)
}
}
}
3 changes: 1 addition & 2 deletions crates/settlement-clients/starknet/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{
collections::HashMap,
future::Future,
path::{Path, PathBuf},
process::{Child, Command, Output, Stdio},
process::{Child, Command, Output},
str::FromStr,
time::Duration,
};
Expand Down Expand Up @@ -183,7 +183,6 @@ impl MadaraCmdBuilder {
"--rpc-port".into(),
format!("{}", self.port.0),
]))
.stdout(Stdio::piped())
.spawn()
.unwrap();

Expand Down
153 changes: 109 additions & 44 deletions crates/settlement-clients/starknet/src/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ use crate::StarknetSettlementClient;
use rstest::{fixture, rstest};
use settlement_client_interface::SettlementClient;
use starknet::{
accounts::{Account, ExecutionEncoding, SingleOwnerAccount},
accounts::{Account, ConnectedAccount, ExecutionEncoding, SingleOwnerAccount},
contract::ContractFactory,
core::types::{
contract::{CompiledClass, SierraClass},
BlockId, BlockTag, DeclareTransactionResult, Felt,
BlockId, BlockTag, DeclareTransactionResult, Felt, FunctionCall, InvokeTransactionResult, StarknetError,
TransactionExecutionStatus, TransactionStatus,
},
macros::felt,
providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider, Url},
macros::{felt, selector},
providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider, ProviderError, Url},
signers::{LocalWallet, SigningKey},
};
use std::env;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use utils::settings::env::EnvSettingsProvider;
use utils::settings::Settings;

Expand All @@ -35,7 +37,6 @@ pub async fn spin_up_madara() -> MadaraCmd {

env::set_current_dir(&project_root).expect("Failed to set working directory");

let _ = env_logger::builder().is_test(true).try_init();
let mut node = MadaraCmdBuilder::new()
.args([
"--network",
Expand All @@ -47,25 +48,69 @@ pub async fn spin_up_madara() -> MadaraCmd {
"--devnet",
"--preset=test",
"--no-l1-sync",
"--rpc-cors",
"all",
])
.run();
println!("check here");
node.wait_for_ready().await;
println!("check here 2");
node
}

// #[fixture]
// async fn setup() -> (SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>, MadaraCmd) {
#[allow(unused)]
async fn wait_for_tx_success(
account: &SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>,
transaction_hash: Felt,
duration: Duration,
) -> bool {
let mut attempt = 0;
loop {
attempt += 1;
let reciept = match account.provider().get_transaction_status(transaction_hash).await {
Ok(reciept) => reciept,
Err(ProviderError::StarknetError(StarknetError::TransactionHashNotFound)) => {
tokio::time::sleep(duration).await;
continue;
}
_ => panic!("Unknown error"),
};

match reciept {
TransactionStatus::Received => (),
TransactionStatus::Rejected => return false,
TransactionStatus::AcceptedOnL2(status) => match status {
TransactionExecutionStatus::Succeeded => return true,
TransactionExecutionStatus::Reverted => return false,
},
TransactionStatus::AcceptedOnL1(status) => match status {
TransactionExecutionStatus::Succeeded => return true,
TransactionExecutionStatus::Reverted => return false,
},
}

if attempt >= 5 {
return false;
}

// This is done, since currently madara does not increment nonce for pending transactions
tokio::time::sleep(duration).await;
}
}

#[fixture]
async fn setup() -> SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet> {
// let madara_process = spin_up_madara().await;
// println!("RPC url {:?}", madara_process.rpc_url);
dotenvy::from_filename_override(".env").expect("Failed to load the .env file");
async fn setup() -> (SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>, MadaraCmd) {
let _ = env_logger::builder().is_test(true).try_init();
dotenvy::from_filename_override(".env.test").expect("Failed to load the .env file");

let madara_process = spin_up_madara().await;
env::set_var("STARKNET_RPC_URL", madara_process.rpc_url.to_string());
println!("RPC url {:?}", madara_process.rpc_url);

let env_settings = EnvSettingsProvider::default();
let rpc_url = Url::parse(&env_settings.get_settings_or_panic("STARKNET_RPC_URL")).unwrap();
println!("RPC url {:?}", rpc_url);
// let endpoint = madara_process.rpc_url.join("/health").unwrap();
// let endpoint = rpc_url.join("/health").unwrap();
// let response = reqwest::get(endpoint.clone()).await.expect("Failed to connect to Provider");
// assert!(response.status().is_success(), "Failed to connect to Provider");

Expand All @@ -82,19 +127,18 @@ async fn setup() -> SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet
// `SingleOwnerAccount` defaults to checking nonce and estimating fees against the latest
// block. Optionally change the target block to pending with the following line:
account.set_block_id(BlockId::Tag(BlockTag::Pending));
// (account, madara_process)
account
(account, madara_process)
}

#[rstest]
#[tokio::test]
// async fn test_deployment(#[future] setup: (SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>, MadaraCmd)) {
async fn test_deployment(#[future] setup: SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>) {
// let (account, madara_process) = setup.await;
let account = setup.await;
async fn test_deployment(#[future] setup: (SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>, MadaraCmd)) {
// async fn test_deployment(#[future] setup: SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>) {
let (account, _) = setup.await;
// let account = setup.await;

// println!("the db being used is {:?}", madara_process.tempdir);
let account = Arc::new(account);
// let account = Arc::new(account);

// NOTE: you will need to declare this class first
let sierra_class: SierraClass = serde_json::from_reader(
Expand All @@ -121,50 +165,71 @@ async fn test_deployment(#[future] setup: SingleOwnerAccount<JsonRpcClient<HttpT

#[rstest]
#[tokio::test]
async fn test_settle(#[future] setup: SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>) {
dotenvy::from_filename(".env.test").expect("Failed to load the .env file");
// let (account, madara_process) = setup.await;
let account = setup.await;

// println!("the db being used is {:?}", madara_process.tempdir);
async fn test_settle(#[future] setup: (SingleOwnerAccount<JsonRpcClient<HttpTransport>, LocalWallet>, MadaraCmd)) {
let (account, _madara_process) = setup.await;
let account = Arc::new(account);

// NOTE: you will need to declare this class first
let sierra_class: SierraClass = serde_json::from_reader(
std::fs::File::open("/Users/bytezorvin/work/karnot/orchestrator/crates/settlement-clients/starknet/src/tests/mock_contracts/target/dev/mock_contracts_Piltover.contract_class.json").unwrap(),
)
.unwrap();
.expect("Failed to parse SierraClass");

let compiled_class: CompiledClass = serde_json::from_reader(
std::fs::File::open("/Users/bytezorvin/work/karnot/orchestrator/crates/settlement-clients/starknet/src/tests/mock_contracts/target/dev/mock_contracts_Piltover.compiled_contract_class.json").unwrap(),
)
.unwrap();
.expect("Failed to parse CompiledClass");

let flattened_class = sierra_class.clone().flatten().unwrap();
let compiled_class_hash = compiled_class.class_hash().unwrap();

// let flattened_class = sierra_class.clone().flatten().unwrap();
// let compiled_class_hash = compiled_class.class_hash().unwrap();
// let DeclareTransactionResult { transaction_hash: _, class_hash } =
// account.declare_v2(Arc::new(flattened_class.clone()), compiled_class_hash).send().await.unwrap();
// assert!(flattened_class.class_hash() == class_hash, "Class hash declared is not same");
let DeclareTransactionResult { transaction_hash: declare_tx_hash, class_hash: _ } =
account.declare_v2(Arc::new(flattened_class.clone()), compiled_class_hash).send().await.unwrap();
println!("declare tx hash {:?}", declare_tx_hash);

// This is done, since currently madara does not increment nonce for pending transactions
// tokio::time::sleep(tokio::time::Duration::from_secs(4)).await;
let is_success = wait_for_tx_success(&account, declare_tx_hash, Duration::from_secs(2)).await;
assert!(is_success, "Declare trasactiion failed");

// let contract_factory = ContractFactory::new(flattened_class.class_hash(), account);
// let deploy_v1 = contract_factory.deploy_v1(vec![], felt!("1122"), false);
// let deployed_address = deploy_v1.deployed_address();
let contract_factory = ContractFactory::new(flattened_class.class_hash(), account.clone());
let deploy_v1 = contract_factory.deploy_v1(vec![], felt!("1122"), false);
let deployed_address = deploy_v1.deployed_address();

let deployed_address = "0x067b25d85c42bae8f3fe833ab5ff97368e1c39019d34f02906e1cc6280f80e50";
env::set_var("STARKNET_CAIRO_CORE_CONTRACT_ADDRESS", deployed_address);
// env::set_var("STARKNET_CAIRO_CORE_CONTRACT_ADDRESS", deployed_address.to_hex_string());
// deploy_v1.send().await.expect("Unable to deploy contract");
env::set_var("STARKNET_CAIRO_CORE_CONTRACT_ADDRESS", deployed_address.to_hex_string());
let InvokeTransactionResult { transaction_hash: deploy_tx_hash } =
deploy_v1.send().await.expect("Unable to deploy contract");

// This is done, since currently madara does not increment nonce for pending transactions
tokio::time::sleep(tokio::time::Duration::from_secs(4)).await;
let is_success = wait_for_tx_success(&account, deploy_tx_hash, Duration::from_secs(2)).await;
assert!(is_success, "Deploy trasaction failed");

let env_settings = EnvSettingsProvider {};
let settlement_client = StarknetSettlementClient::new_with_settings(&env_settings).await;
let onchain_data_hash = [1; 32];
let mut program_output = Vec::with_capacity(32);
program_output.fill(onchain_data_hash);
settlement_client.update_state_calldata(program_output, onchain_data_hash, 1).await.unwrap();
let update_state_tx_hash = settlement_client
.update_state_calldata(program_output, onchain_data_hash, [1, 1])
.await
.expect("Sending Update state");

let is_success = wait_for_tx_success(
&account,
Felt::from_hex(&update_state_tx_hash).expect("Incorrect transaction hash"),
Duration::from_secs(2),
)
.await;
assert!(is_success, "Update state transaction failed/reverted");

let call_result = account
.provider()
.call(
FunctionCall {
contract_address: deployed_address,
entry_point_selector: selector!("get_is_updated"),
calldata: vec![Felt::from_bytes_be_slice(&onchain_data_hash)],
},
BlockId::Tag(BlockTag::Latest),
)
.await
.expect("failed to call the contract");
assert!(call_result[0] == true.into(), "Should be updated");
}

0 comments on commit 003b3ae

Please sign in to comment.