[test] handle_commit_{new_process, new_state}
This commit is contained in:
parent
cfbf08faa4
commit
74863aac3b
@ -19,3 +19,6 @@ tokio = { version = "1.0.0", features = ["io-util", "rt-multi-thread", "macros",
|
||||
tokio-stream = "0.1"
|
||||
tokio-tungstenite = "0.21.0"
|
||||
zeromq = "0.4.1"
|
||||
|
||||
[dev-dependencies]
|
||||
mockall = "0.13.0"
|
||||
|
301
src/commit.rs
301
src/commit.rs
@ -203,4 +203,305 @@ fn commit_new_transaction(
|
||||
Ok(commited_in)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use bitcoincore_rpc::bitcoin::hex::DisplayHex;
|
||||
use sdk_common::pcd::Member;
|
||||
use sdk_common::pcd::RoleDefinition;
|
||||
use sdk_common::pcd::ValidationRule;
|
||||
use sdk_common::sp_client::silentpayments::utils::SilentPaymentAddress;
|
||||
use serde_json::json;
|
||||
use mockall::predicate::*;
|
||||
use mockall::mock;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Mutex, Arc};
|
||||
use bitcoincore_rpc::bitcoin::*;
|
||||
use crate::daemon::RpcCall;
|
||||
use std::sync::OnceLock;
|
||||
use sdk_common::sp_client::bitcoin::consensus::serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
const LOCAL_ADDRESS: &str = "sprt1qq222dhaxlzmjft2pa7qtspw2aw55vwfmtnjyllv5qrsqwm3nufxs6q7t88jf9asvd7rxhczt87de68du3jhem54xvqxy80wc6ep7lauxacsrq79v";
|
||||
const INIT_TRANSACTION: &str = "02000000000102b01b832bf34cf87583c628839c5316546646dcd4939e339c1d83e693216cdfa00100000000fdffffffdd1ca865b199accd4801634488fca87e0cf81b36ee7e9bec526a8f922539b8670000000000fdffffff0200e1f505000000001600140798fac9f310cefad436ea928f0bdacf03a11be544e0f5050000000016001468a66f38e7c2c9e367577d6fad8532ae2c728ed2014043764b77de5041f80d19e3d872f205635f87486af015c00d2a3b205c694a0ae1cbc60e70b18bcd4470abbd777de63ae52600aba8f5ad1334cdaa6bcd931ab78b0140b56dd8e7ac310d6dcbc3eff37f111ced470990d911b55cd6ff84b74b579c17d0bba051ec23b738eeeedba405a626d95f6bdccb94c626db74c57792254bfc5a7c00000000";
|
||||
|
||||
// Define the mock for Daemon with the required methods
|
||||
mock! {
|
||||
#[derive(Debug)]
|
||||
pub Daemon {}
|
||||
|
||||
impl RpcCall for Daemon {
|
||||
fn connect(
|
||||
rpcwallet: Option<String>,
|
||||
rpc_url: String,
|
||||
network: bitcoincore_rpc::bitcoin::Network,
|
||||
) -> Result<Self> where Self: Sized;
|
||||
|
||||
fn estimate_fee(&self, nblocks: u16) -> Result<Amount>;
|
||||
|
||||
fn get_relay_fee(&self) -> Result<Amount>;
|
||||
|
||||
fn get_current_height(&self) -> Result<u64>;
|
||||
|
||||
fn get_block(&self, block_hash: BlockHash) -> Result<Block>;
|
||||
|
||||
fn get_filters(&self, block_height: u32) -> Result<(u32, BlockHash, bip158::BlockFilter)>;
|
||||
|
||||
fn list_unspent_from_to(
|
||||
&self,
|
||||
minamt: Option<Amount>,
|
||||
) -> Result<Vec<bitcoincore_rpc::json::ListUnspentResultEntry>>;
|
||||
|
||||
fn create_psbt(
|
||||
&self,
|
||||
unspents: &[bitcoincore_rpc::json::ListUnspentResultEntry],
|
||||
spk: ScriptBuf,
|
||||
network: Network,
|
||||
) -> Result<String>;
|
||||
|
||||
fn process_psbt(&self, psbt: String) -> Result<String>;
|
||||
|
||||
fn finalize_psbt(&self, psbt: String) -> Result<String>;
|
||||
|
||||
fn get_network(&self) -> Result<Network>;
|
||||
|
||||
fn test_mempool_accept(
|
||||
&self,
|
||||
tx: &Transaction,
|
||||
) -> Result<crate::bitcoin_json::TestMempoolAcceptResult>;
|
||||
|
||||
fn broadcast(&self, tx: &Transaction) -> Result<Txid>;
|
||||
|
||||
fn get_transaction_info(
|
||||
&self,
|
||||
txid: &Txid,
|
||||
blockhash: Option<BlockHash>,
|
||||
) -> Result<Value>;
|
||||
|
||||
fn get_transaction_hex(
|
||||
&self,
|
||||
txid: &Txid,
|
||||
blockhash: Option<BlockHash>,
|
||||
) -> Result<Value>;
|
||||
|
||||
fn get_transaction(
|
||||
&self,
|
||||
txid: &Txid,
|
||||
blockhash: Option<BlockHash>,
|
||||
) -> Result<Transaction>;
|
||||
|
||||
fn get_block_txids(&self, blockhash: BlockHash) -> Result<Vec<Txid>>;
|
||||
|
||||
fn get_mempool_txids(&self) -> Result<Vec<Txid>>;
|
||||
|
||||
fn get_mempool_entries(
|
||||
&self,
|
||||
txids: &[Txid],
|
||||
) -> Result<Vec<Result<bitcoincore_rpc::json::GetMempoolEntryResult>>>;
|
||||
|
||||
fn get_mempool_transactions(
|
||||
&self,
|
||||
txids: &[Txid],
|
||||
) -> Result<Vec<Result<Transaction>>>;
|
||||
}
|
||||
}
|
||||
|
||||
mock! {
|
||||
#[derive(Debug)]
|
||||
pub SpWallet {
|
||||
fn get_receiving_address(&self) -> Result<String>;
|
||||
}
|
||||
}
|
||||
|
||||
mock! {
|
||||
#[derive(Debug)]
|
||||
pub SilentPaymentWallet {
|
||||
fn get_sp_wallet(&self) -> Result<MockSpWallet>;
|
||||
}
|
||||
}
|
||||
|
||||
static WALLET: OnceLock<MockSilentPaymentWallet> = OnceLock::new();
|
||||
|
||||
pub fn initialize_static_variables() {
|
||||
if DAEMON.get().is_none() {
|
||||
let mut daemon = MockDaemon::new();
|
||||
daemon.expect_broadcast()
|
||||
.withf(|tx: &Transaction| serialize(tx).to_lower_hex_string() == INIT_TRANSACTION)
|
||||
.returning(|tx| Ok(tx.txid()));
|
||||
DAEMON.set(Mutex::new(Box::new(daemon))).expect("DAEMON should only be initialized once");
|
||||
println!("Initialized DAEMON");
|
||||
}
|
||||
|
||||
if WALLET.get().is_none() {
|
||||
let mut wallet = MockSilentPaymentWallet::new();
|
||||
wallet.expect_get_sp_wallet().returning(|| Ok(MockSpWallet::new()));
|
||||
WALLET.set(wallet).expect("WALLET should only be initialized once");
|
||||
println!("Initialized WALLET");
|
||||
}
|
||||
|
||||
if CACHEDPROCESSES.get().is_none() {
|
||||
CACHEDPROCESSES
|
||||
.set(Mutex::new(HashMap::new()))
|
||||
.expect("CACHEDPROCESSES should only be initialized once");
|
||||
|
||||
println!("Initialized CACHEDPROCESSES");
|
||||
}
|
||||
}
|
||||
|
||||
fn mock_commit_msg(init_tx: Transaction, first: bool) -> CommitMessage {
|
||||
let field_name = "roles".to_owned();
|
||||
let member = Member::new(vec![SilentPaymentAddress::try_from(LOCAL_ADDRESS).unwrap()]).unwrap();
|
||||
let validation_rule = ValidationRule::new(1.0, vec![field_name.clone()], 1.0).unwrap();
|
||||
|
||||
let role_def = RoleDefinition {
|
||||
members: vec![member],
|
||||
validation_rules: vec![validation_rule]
|
||||
};
|
||||
let roles = HashMap::from([(String::from("role_name"), role_def)]);
|
||||
let pcd_commitment = json!({field_name: "b30212b9649054b71f938fbe0d1c08e72de95bdb12b8008082795c6e9c4ad26a"});
|
||||
|
||||
let init_tx = if first { serialize(&init_tx).to_lower_hex_string() } else { OutPoint::new(init_tx.txid(), 0).to_string() };
|
||||
|
||||
let commit_msg = CommitMessage {
|
||||
init_tx,
|
||||
roles: roles.clone(),
|
||||
validation_tokens: vec![],
|
||||
pcd_commitment: pcd_commitment.clone(),
|
||||
error: None,
|
||||
};
|
||||
|
||||
commit_msg
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_handle_commit_new_process() {
|
||||
initialize_static_variables();
|
||||
let init_tx = deserialize::<Transaction>(&Vec::from_hex(INIT_TRANSACTION).unwrap()).unwrap();
|
||||
let init_txid = init_tx.txid();
|
||||
let init_commitment = OutPoint::new(init_txid, 0);
|
||||
|
||||
let commit_msg = mock_commit_msg(init_tx, true);
|
||||
|
||||
let roles = commit_msg.roles.clone();
|
||||
let pcd_commitment = commit_msg.pcd_commitment.clone();
|
||||
|
||||
let empty_state = ProcessState {
|
||||
commited_in: init_commitment,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let result = handle_commit_request(commit_msg);
|
||||
|
||||
assert_eq!(result.unwrap(), init_commitment);
|
||||
|
||||
let cache = CACHEDPROCESSES.get().unwrap().lock().unwrap();
|
||||
let updated_process = cache.get(&init_commitment);
|
||||
|
||||
assert!(updated_process.is_some());
|
||||
let concurrent_states = updated_process.unwrap().get_latest_concurrent_states().unwrap();
|
||||
|
||||
// Constructing the roles_map that was inserted in the process
|
||||
let roles_object = serde_json::to_value(roles).unwrap();
|
||||
let mut roles_map = Map::new();
|
||||
roles_map.insert("roles".to_owned(), roles_object);
|
||||
let new_state = ProcessState {
|
||||
commited_in: init_commitment,
|
||||
pcd_commitment,
|
||||
encrypted_pcd: Value::Object(roles_map),
|
||||
..Default::default()
|
||||
};
|
||||
let target = vec![&empty_state, &new_state];
|
||||
|
||||
assert_eq!(concurrent_states, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_handle_commit_new_state() {
|
||||
initialize_static_variables();
|
||||
let init_tx = deserialize::<Transaction>(&Vec::from_hex(INIT_TRANSACTION).unwrap()).unwrap();
|
||||
let init_txid = init_tx.txid();
|
||||
let init_commitment = OutPoint::new(init_txid, 0);
|
||||
|
||||
let commit_msg = mock_commit_msg(init_tx, false);
|
||||
|
||||
let roles = commit_msg.roles.clone();
|
||||
let pcd_commitment = commit_msg.pcd_commitment.clone();
|
||||
|
||||
let empty_state = ProcessState {
|
||||
commited_in: init_commitment,
|
||||
..Default::default()
|
||||
};
|
||||
let process = Process::new(vec![empty_state.clone()], vec![]);
|
||||
CACHEDPROCESSES.get().unwrap().lock().unwrap().insert(init_commitment, process);
|
||||
|
||||
let result = handle_commit_request(commit_msg);
|
||||
|
||||
assert_eq!(result.unwrap(), init_commitment);
|
||||
|
||||
let cache = CACHEDPROCESSES.get().unwrap().lock().unwrap();
|
||||
let updated_process = cache.get(&init_commitment);
|
||||
|
||||
assert!(updated_process.is_some());
|
||||
let concurrent_states = updated_process.unwrap().get_latest_concurrent_states().unwrap();
|
||||
|
||||
let roles_object = serde_json::to_value(roles).unwrap();
|
||||
let mut roles_map = Map::new();
|
||||
roles_map.insert("roles".to_owned(), roles_object);
|
||||
let new_state = ProcessState {
|
||||
commited_in: init_commitment,
|
||||
pcd_commitment,
|
||||
encrypted_pcd: Value::Object(roles_map),
|
||||
..Default::default()
|
||||
};
|
||||
let target = vec![&empty_state, &new_state];
|
||||
|
||||
assert_eq!(concurrent_states, target);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_handle_commit_request_invalid_init_tx() {
|
||||
// let commit_msg = CommitMessage {
|
||||
// init_tx: "invalid_tx_hex".to_string(),
|
||||
// roles: HashMap::new(),
|
||||
// validation_tokens: vec![],
|
||||
// pcd_commitment: json!({"roles": "expected_roles"}).as_object().unwrap().clone(),
|
||||
// };
|
||||
|
||||
// // Call the function under test
|
||||
// let result = handle_commit_request(commit_msg);
|
||||
|
||||
// // Assertions for error
|
||||
// assert!(result.is_err());
|
||||
// assert_eq!(result.unwrap_err().to_string(), "init_tx must be a valid transaction or txid");
|
||||
// }
|
||||
|
||||
// // Example test for adding a new state to an existing commitment
|
||||
// #[test]
|
||||
// fn test_handle_commit_request_add_state() {
|
||||
// // Set up data for adding a state to an existing commitment
|
||||
// let commit_msg = CommitMessage {
|
||||
// init_tx: "existing_outpoint_hex".to_string(),
|
||||
// roles: HashMap::new(),
|
||||
// validation_tokens: vec![],
|
||||
// pcd_commitment: json!({"roles": "expected_roles"}).as_object().unwrap().clone(),
|
||||
// };
|
||||
|
||||
// // Mock daemon and cache initialization
|
||||
// let mut daemon = MockDaemon::new();
|
||||
// daemon.expect_broadcast().returning(|_| Ok(Txid::new()));
|
||||
// DAEMON.set(Arc::new(Mutex::new(daemon))).unwrap();
|
||||
|
||||
// let process_state = Process::new(vec![], vec![]);
|
||||
// CACHEDPROCESSES.lock().unwrap().insert(OutPoint::new("mock_txid", 0), process_state);
|
||||
|
||||
// // Run the function
|
||||
// let result = handle_commit_request(commit_msg);
|
||||
|
||||
// // Assert success and that a new state was added
|
||||
// assert!(result.is_ok());
|
||||
// assert_eq!(result.unwrap(), OutPoint::new("mock_txid", 0));
|
||||
// }
|
||||
|
||||
// // Additional tests for errors and validation tokens would follow a similar setup
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user