mirror of
https://github.com/mimblewimble/mwixnet.git
synced 2025-01-20 19:11:09 +03:00
add test for every swap failure scenario
This commit is contained in:
parent
2e02d67dbc
commit
6f626ac11e
3 changed files with 312 additions and 87 deletions
15
src/onion.rs
15
src/onion.rs
|
@ -214,20 +214,19 @@ pub mod test_util {
|
|||
use crate::secp::{Commitment, PublicKey, Secp256k1, SecretKey, SharedSecret};
|
||||
use crate::types::Payload;
|
||||
|
||||
use crate::secp;
|
||||
use chacha20::cipher::StreamCipher;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Hop {
|
||||
pub pubkey: PublicKey,
|
||||
pub payload: Payload,
|
||||
}
|
||||
|
||||
/// Create an Onion for the Commitment, encrypting the payload for each hop
|
||||
pub fn create_onion(
|
||||
commitment: &Commitment,
|
||||
session_key: &SecretKey,
|
||||
hops: &Vec<Hop>,
|
||||
) -> Result<Onion> {
|
||||
pub fn create_onion(commitment: &Commitment, hops: &Vec<Hop>) -> Result<Onion> {
|
||||
let secp = Secp256k1::new();
|
||||
let session_key = secp::random_secret();
|
||||
let mut ephemeral_key = session_key.clone();
|
||||
|
||||
let mut shared_secrets: Vec<SharedSecret> = Vec::new();
|
||||
|
@ -251,7 +250,7 @@ pub mod test_util {
|
|||
}
|
||||
|
||||
let onion = Onion {
|
||||
ephemeral_pubkey: PublicKey::from_secret_key(&secp, session_key)?,
|
||||
ephemeral_pubkey: PublicKey::from_secret_key(&secp, &session_key)?,
|
||||
commit: commitment.clone(),
|
||||
enc_payloads,
|
||||
};
|
||||
|
@ -287,9 +286,7 @@ pub mod tests {
|
|||
let blind = secp::random_secret();
|
||||
let commitment = secp::commit(in_value, &blind).unwrap();
|
||||
|
||||
let session_key = secp::random_secret();
|
||||
let mut hops: Vec<Hop> = Vec::new();
|
||||
|
||||
let mut keys: Vec<secp::SecretKey> = Vec::new();
|
||||
let mut final_commit = secp::commit(out_value, &blind).unwrap();
|
||||
let mut final_blind = blind.clone();
|
||||
|
@ -327,7 +324,7 @@ pub mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
let mut onion_packet = test_util::create_onion(&commitment, &session_key, &hops).unwrap();
|
||||
let mut onion_packet = test_util::create_onion(&commitment, &hops).unwrap();
|
||||
|
||||
let mut payload = Payload {
|
||||
excess: secp::random_secret(),
|
||||
|
|
|
@ -201,7 +201,7 @@ mod tests {
|
|||
#[test]
|
||||
fn swap_success() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let commitment = secp::commit(1234, &secp::random_secret())?;
|
||||
let onion = test_util::create_onion(&commitment, &secp::random_secret(), &vec![])?;
|
||||
let onion = test_util::create_onion(&commitment, &vec![])?;
|
||||
let comsig = ComSignature::sign(1234, &secp::random_secret(), &onion.serialize()?)?;
|
||||
let swap = SwapReq {
|
||||
onion: onion.clone(),
|
||||
|
@ -241,7 +241,7 @@ mod tests {
|
|||
#[test]
|
||||
fn swap_utxo_missing() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let commitment = secp::commit(1234, &secp::random_secret())?;
|
||||
let onion = test_util::create_onion(&commitment, &secp::random_secret(), &vec![])?;
|
||||
let onion = test_util::create_onion(&commitment, &vec![])?;
|
||||
let comsig = ComSignature::sign(1234, &secp::random_secret(), &onion.serialize()?)?;
|
||||
let swap = SwapReq {
|
||||
onion: onion.clone(),
|
||||
|
|
380
src/server.rs
380
src/server.rs
|
@ -35,8 +35,10 @@ pub enum SwapError {
|
|||
InvalidPayloadLength { expected: usize, found: usize },
|
||||
#[error("Commitment Signature is invalid")]
|
||||
InvalidComSignature,
|
||||
#[error("Rangeproof is missing or invalid")]
|
||||
#[error("Rangeproof is invalid")]
|
||||
InvalidRangeproof,
|
||||
#[error("Rangeproof is required but was not supplied")]
|
||||
MissingRangeproof,
|
||||
#[error("Output {commit:?} does not exist, or is already spent.")]
|
||||
CoinNotFound { commit: Commitment },
|
||||
#[error("Output {commit:?} is already in the swap list.")]
|
||||
|
@ -49,12 +51,19 @@ pub enum SwapError {
|
|||
UnknownError(String),
|
||||
}
|
||||
|
||||
/// A MWixnet server
|
||||
pub trait Server: Send + Sync {
|
||||
/// Submit a new output to be swapped.
|
||||
fn swap(&self, onion: &Onion, comsig: &ComSignature) -> Result<(), SwapError>;
|
||||
|
||||
/// Iterate through all saved submissions, filter out any inputs that are no longer spendable,
|
||||
/// and assemble the coinswap transaction, posting the transaction to the configured node.
|
||||
///
|
||||
/// Currently only a single mix node is used. Milestone 3 will include support for multiple mix nodes.
|
||||
fn execute_round(&self) -> crate::error::Result<()>;
|
||||
}
|
||||
|
||||
/// The standard MWixnet server implementation
|
||||
#[derive(Clone)]
|
||||
pub struct ServerImpl {
|
||||
server_config: ServerConfig,
|
||||
|
@ -91,7 +100,6 @@ impl ServerImpl {
|
|||
}
|
||||
|
||||
impl Server for ServerImpl {
|
||||
/// Submit a new output to be swapped.
|
||||
fn swap(&self, onion: &Onion, comsig: &ComSignature) -> Result<(), SwapError> {
|
||||
// milestone 3: check that enc_payloads length matches number of configured servers
|
||||
if onion.enc_payloads.len() != 1 {
|
||||
|
@ -142,7 +150,7 @@ impl Server for ServerImpl {
|
|||
.map_err(|_| SwapError::InvalidRangeproof)?;
|
||||
} else {
|
||||
// milestone 3: only the last hop will have a rangeproof
|
||||
return Err(SwapError::InvalidRangeproof);
|
||||
return Err(SwapError::MissingRangeproof);
|
||||
}
|
||||
|
||||
let mut locked = self.submissions.lock().unwrap();
|
||||
|
@ -166,10 +174,6 @@ impl Server for ServerImpl {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Iterate through all saved submissions, filter out any inputs that are no longer spendable,
|
||||
/// and assemble the coinswap transaction, posting the transaction to the configured node.
|
||||
///
|
||||
/// Currently only a single mix node is used. Milestone 3 will include support for multiple mix nodes.
|
||||
fn execute_round(&self) -> crate::error::Result<()> {
|
||||
let mut locked_state = self.submissions.lock().unwrap();
|
||||
let next_block_height = self.node.get_chain_height()? + 1;
|
||||
|
@ -272,17 +276,34 @@ mod tests {
|
|||
use crate::node::mock::MockGrinNode;
|
||||
use crate::onion::test_util::{self, Hop};
|
||||
use crate::onion::Onion;
|
||||
use crate::secp::{self, ComSignature, PublicKey, Secp256k1, SecretKey};
|
||||
use crate::secp::{
|
||||
self, ComSignature, Commitment, PublicKey, RangeProof, Secp256k1, SecretKey,
|
||||
};
|
||||
use crate::server::{Server, ServerImpl, Submission, SwapError};
|
||||
use crate::types::Payload;
|
||||
use crate::wallet::mock::MockWallet;
|
||||
|
||||
use grin_core::core::{Committed, FeeFields, Input, OutputFeatures, Transaction};
|
||||
use grin_core::core::{Committed, FeeFields, Input, OutputFeatures, Transaction, Weighting};
|
||||
use grin_core::global::{self, ChainTypes};
|
||||
use std::net::TcpListener;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn new_config(server_key: &SecretKey) -> ServerConfig {
|
||||
ServerConfig {
|
||||
macro_rules! assert_error_type {
|
||||
($result:expr, $error_type:pat) => {
|
||||
assert!($result.is_err());
|
||||
assert!(if let $error_type = $result.unwrap_err() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
fn new_server(
|
||||
server_key: &SecretKey,
|
||||
utxos: &Vec<&Commitment>,
|
||||
) -> (ServerImpl, Arc<MockGrinNode>) {
|
||||
let config = ServerConfig {
|
||||
key: server_key.clone(),
|
||||
interval_s: 1,
|
||||
addr: TcpListener::bind("127.0.0.1:0")
|
||||
|
@ -293,53 +314,70 @@ mod tests {
|
|||
grin_node_secret_path: None,
|
||||
wallet_owner_url: "127.0.0.1:3420".parse().unwrap(),
|
||||
wallet_owner_secret_path: None,
|
||||
};
|
||||
let wallet = Arc::new(MockWallet {});
|
||||
let mut mut_node = MockGrinNode::new();
|
||||
for utxo in utxos {
|
||||
mut_node.add_default_utxo(&utxo);
|
||||
}
|
||||
let node = Arc::new(mut_node);
|
||||
|
||||
let server = ServerImpl::new(config, wallet.clone(), node.clone());
|
||||
(server, node)
|
||||
}
|
||||
|
||||
fn proof(value: u64, fee: u64, input_blind: &SecretKey, hop_excess: &SecretKey) -> RangeProof {
|
||||
let secp = Secp256k1::new();
|
||||
let nonce = secp::random_secret();
|
||||
|
||||
let mut blind = input_blind.clone();
|
||||
blind.add_assign(&secp, &hop_excess).unwrap();
|
||||
|
||||
secp.bullet_proof(
|
||||
value - fee,
|
||||
blind.clone(),
|
||||
nonce.clone(),
|
||||
nonce.clone(),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_hop(
|
||||
server_key: &SecretKey,
|
||||
hop_excess: &SecretKey,
|
||||
fee: u64,
|
||||
proof: Option<RangeProof>,
|
||||
) -> Hop {
|
||||
let secp = Secp256k1::new();
|
||||
Hop {
|
||||
pubkey: PublicKey::from_secret_key(&secp, &server_key).unwrap(),
|
||||
payload: Payload {
|
||||
excess: hop_excess.clone(),
|
||||
fee: FeeFields::from(fee as u32),
|
||||
rangeproof: proof,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Single hop to demonstrate request validation and onion unwrapping.
|
||||
#[test]
|
||||
fn swap_lifecycle() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let secp = Secp256k1::with_caps(secp256k1zkp::ContextFlag::Commit);
|
||||
let server_key = secp::random_secret();
|
||||
|
||||
let value: u64 = 200_000_000;
|
||||
let fee: u64 = 50_000_000;
|
||||
let blind = secp::random_secret();
|
||||
let input_commit = secp::commit(value, &blind)?;
|
||||
|
||||
let server_key = secp::random_secret();
|
||||
let hop_excess = secp::random_secret();
|
||||
let nonce = secp::random_secret();
|
||||
let proof = proof(value, fee, &blind, &hop_excess);
|
||||
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
|
||||
|
||||
let mut final_blind = blind.clone();
|
||||
final_blind.add_assign(&secp, &hop_excess).unwrap();
|
||||
let proof = secp.bullet_proof(
|
||||
value - fee,
|
||||
final_blind.clone(),
|
||||
nonce.clone(),
|
||||
nonce.clone(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||
|
||||
let hop = Hop {
|
||||
pubkey: PublicKey::from_secret_key(&secp, &server_key)?,
|
||||
payload: Payload {
|
||||
excess: hop_excess.clone(),
|
||||
fee: FeeFields::from(fee as u32),
|
||||
rangeproof: Some(proof),
|
||||
},
|
||||
};
|
||||
let hops: Vec<Hop> = vec![hop];
|
||||
let session_key = secp::random_secret();
|
||||
let onion_packet = test_util::create_onion(&input_commit, &session_key, &hops)?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion_packet.serialize()?)?;
|
||||
|
||||
let wallet = Arc::new(MockWallet {});
|
||||
let mut mut_node = MockGrinNode::new();
|
||||
mut_node.add_default_utxo(&input_commit);
|
||||
let node = Arc::new(mut_node);
|
||||
|
||||
let server = ServerImpl::new(new_config(&server_key), wallet.clone(), node.clone());
|
||||
server.swap(&onion_packet, &comsig)?;
|
||||
let (server, node) = new_server(&server_key, &vec![&input_commit]);
|
||||
server.swap(&onion, &comsig)?;
|
||||
|
||||
// Make sure entry is added to server.
|
||||
let output_commit = secp::add_excess(&input_commit, &hop_excess)?;
|
||||
|
@ -352,7 +390,7 @@ mod tests {
|
|||
input: Input::new(OutputFeatures::Plain, input_commit.clone()),
|
||||
fee,
|
||||
onion: Onion {
|
||||
ephemeral_pubkey: test_util::next_ephemeral_pubkey(&onion_packet, &server_key)?,
|
||||
ephemeral_pubkey: test_util::next_ephemeral_pubkey(&onion, &server_key)?,
|
||||
commit: output_commit.clone(),
|
||||
enc_payloads: vec![],
|
||||
},
|
||||
|
@ -374,47 +412,41 @@ mod tests {
|
|||
let posted_txns = node.get_posted_txns();
|
||||
assert_eq!(posted_txns.len(), 1);
|
||||
let posted_txn: Transaction = posted_txns.into_iter().next().unwrap();
|
||||
let posted_input = posted_txn.inputs_committed().into_iter().next().unwrap();
|
||||
assert_eq!(input_commit, posted_input);
|
||||
assert!(posted_txn.inputs_committed().contains(&input_commit));
|
||||
assert!(posted_txn.outputs_committed().contains(&output_commit));
|
||||
// todo: check that outputs also contain the commitment generated by our wallet
|
||||
|
||||
global::set_local_chain_type(ChainTypes::AutomatedTesting);
|
||||
posted_txn.validate(Weighting::AsTransaction)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns "Commitment not found" when there's no matching output in the UTXO set.
|
||||
/// Returns InvalidPayloadLength when too many payloads are provided.
|
||||
#[test]
|
||||
fn swap_utxo_missing() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let secp = Secp256k1::new();
|
||||
let server_key = secp::random_secret();
|
||||
|
||||
fn swap_too_many_payloads() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let value: u64 = 200_000_000;
|
||||
let fee: u64 = 50_000_000;
|
||||
let blind = secp::random_secret();
|
||||
let commitment = secp::commit(value, &blind)?;
|
||||
let input_commit = secp::commit(value, &blind)?;
|
||||
|
||||
let hop = Hop {
|
||||
pubkey: PublicKey::from_secret_key(&secp, &server_key)?,
|
||||
payload: Payload {
|
||||
excess: secp::random_secret(),
|
||||
fee: FeeFields::from(fee as u32),
|
||||
rangeproof: None,
|
||||
},
|
||||
};
|
||||
let hops: Vec<Hop> = vec![hop];
|
||||
let session_key = secp::random_secret();
|
||||
let onion_packet = test_util::create_onion(&commitment, &session_key, &hops)?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion_packet.serialize()?)?;
|
||||
let server_key = secp::random_secret();
|
||||
let hop_excess = secp::random_secret();
|
||||
let proof = proof(value, fee, &blind, &hop_excess);
|
||||
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
|
||||
|
||||
let wallet = Arc::new(MockWallet {});
|
||||
let node = Arc::new(MockGrinNode::new());
|
||||
let hops: Vec<Hop> = vec![hop.clone(), hop.clone()]; // Multiple payloads
|
||||
let onion = test_util::create_onion(&input_commit, &hops)?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||
|
||||
let server = ServerImpl::new(new_config(&server_key), wallet.clone(), node.clone());
|
||||
let result = server.swap(&onion_packet, &comsig);
|
||||
assert!(result.is_err());
|
||||
let (server, _node) = new_server(&server_key, &vec![&input_commit]);
|
||||
let result = server.swap(&onion, &comsig);
|
||||
assert_eq!(
|
||||
SwapError::CoinNotFound {
|
||||
commit: commitment.clone()
|
||||
},
|
||||
result.unwrap_err()
|
||||
Err(SwapError::InvalidPayloadLength {
|
||||
expected: 1,
|
||||
found: 2
|
||||
}),
|
||||
result
|
||||
);
|
||||
|
||||
// Make sure no entry is added to server.submissions
|
||||
|
@ -423,5 +455,201 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Test bulletproof verification and test minimum fee
|
||||
/// Returns InvalidComSignature when ComSignature fails to verify.
|
||||
#[test]
|
||||
fn swap_invalid_com_signature() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let value: u64 = 200_000_000;
|
||||
let fee: u64 = 50_000_000;
|
||||
let blind = secp::random_secret();
|
||||
let input_commit = secp::commit(value, &blind)?;
|
||||
|
||||
let server_key = secp::random_secret();
|
||||
let hop_excess = secp::random_secret();
|
||||
let proof = proof(value, fee, &blind, &hop_excess);
|
||||
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
|
||||
|
||||
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
|
||||
|
||||
let wrong_blind = secp::random_secret();
|
||||
let comsig = ComSignature::sign(value, &wrong_blind, &onion.serialize()?)?;
|
||||
|
||||
let (server, _node) = new_server(&server_key, &vec![&input_commit]);
|
||||
let result = server.swap(&onion, &comsig);
|
||||
assert_eq!(Err(SwapError::InvalidComSignature), result);
|
||||
|
||||
// Make sure no entry is added to server.submissions
|
||||
assert!(server.submissions.lock().unwrap().is_empty());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns InvalidRangeProof when the rangeproof fails to verify for the commitment.
|
||||
#[test]
|
||||
fn swap_invalid_rangeproof() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let value: u64 = 200_000_000;
|
||||
let fee: u64 = 50_000_000;
|
||||
let blind = secp::random_secret();
|
||||
let input_commit = secp::commit(value, &blind)?;
|
||||
|
||||
let server_key = secp::random_secret();
|
||||
let hop_excess = secp::random_secret();
|
||||
let wrong_value = value + 10_000_000;
|
||||
let proof = proof(wrong_value, fee, &blind, &hop_excess);
|
||||
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
|
||||
|
||||
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||
|
||||
let (server, _node) = new_server(&server_key, &vec![&input_commit]);
|
||||
let result = server.swap(&onion, &comsig);
|
||||
assert_eq!(Err(SwapError::InvalidRangeproof), result);
|
||||
|
||||
// Make sure no entry is added to server.submissions
|
||||
assert!(server.submissions.lock().unwrap().is_empty());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns MissingRangeproof when no rangeproof is provided.
|
||||
#[test]
|
||||
fn swap_missing_rangeproof() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let value: u64 = 200_000_000;
|
||||
let fee: u64 = 50_000_000;
|
||||
let blind = secp::random_secret();
|
||||
let input_commit = secp::commit(value, &blind)?;
|
||||
|
||||
let server_key = secp::random_secret();
|
||||
let hop_excess = secp::random_secret();
|
||||
let hop = new_hop(&server_key, &hop_excess, fee, None);
|
||||
|
||||
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||
|
||||
let (server, _node) = new_server(&server_key, &vec![&input_commit]);
|
||||
let result = server.swap(&onion, &comsig);
|
||||
assert_eq!(Err(SwapError::MissingRangeproof), result);
|
||||
|
||||
// Make sure no entry is added to server.submissions
|
||||
assert!(server.submissions.lock().unwrap().is_empty());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns CoinNotFound when there's no matching output in the UTXO set.
|
||||
#[test]
|
||||
fn swap_utxo_missing() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let value: u64 = 200_000_000;
|
||||
let fee: u64 = 50_000_000;
|
||||
let blind = secp::random_secret();
|
||||
let input_commit = secp::commit(value, &blind)?;
|
||||
|
||||
let server_key = secp::random_secret();
|
||||
let hop_excess = secp::random_secret();
|
||||
let proof = proof(value, fee, &blind, &hop_excess);
|
||||
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
|
||||
|
||||
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||
|
||||
let (server, _node) = new_server(&server_key, &vec![]);
|
||||
let result = server.swap(&onion, &comsig);
|
||||
assert_eq!(
|
||||
Err(SwapError::CoinNotFound {
|
||||
commit: input_commit.clone()
|
||||
}),
|
||||
result
|
||||
);
|
||||
|
||||
// Make sure no entry is added to server.submissions
|
||||
assert!(server.submissions.lock().unwrap().is_empty());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns AlreadySwapped when trying to swap the same commitment multiple times.
|
||||
#[test]
|
||||
fn swap_already_swapped() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let value: u64 = 200_000_000;
|
||||
let fee: u64 = 50_000_000;
|
||||
let blind = secp::random_secret();
|
||||
let input_commit = secp::commit(value, &blind)?;
|
||||
|
||||
let server_key = secp::random_secret();
|
||||
let hop_excess = secp::random_secret();
|
||||
let proof = proof(value, fee, &blind, &hop_excess);
|
||||
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
|
||||
|
||||
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||
|
||||
let (server, _node) = new_server(&server_key, &vec![&input_commit]);
|
||||
server.swap(&onion, &comsig)?;
|
||||
|
||||
// Call swap a second time
|
||||
let result = server.swap(&onion, &comsig);
|
||||
assert_eq!(
|
||||
Err(SwapError::AlreadySwapped {
|
||||
commit: input_commit.clone()
|
||||
}),
|
||||
result
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns PeelOnionFailure when a failure occurs trying to decrypt the onion payload.
|
||||
#[test]
|
||||
fn swap_peel_onion_failure() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let value: u64 = 200_000_000;
|
||||
let fee: u64 = 50_000_000;
|
||||
let blind = secp::random_secret();
|
||||
let input_commit = secp::commit(value, &blind)?;
|
||||
|
||||
let server_key = secp::random_secret();
|
||||
let hop_excess = secp::random_secret();
|
||||
let proof = proof(value, fee, &blind, &hop_excess);
|
||||
|
||||
let wrong_server_key = secp::random_secret();
|
||||
let hop = new_hop(&wrong_server_key, &hop_excess, fee, Some(proof));
|
||||
|
||||
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||
|
||||
let (server, _node) = new_server(&server_key, &vec![&input_commit]);
|
||||
let result = server.swap(&onion, &comsig);
|
||||
|
||||
assert!(result.is_err());
|
||||
assert_error_type!(result, SwapError::PeelOnionFailure(_));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns FeeTooLow when the minimum fee is not met.
|
||||
#[test]
|
||||
fn swap_fee_too_low() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let value: u64 = 200_000_000;
|
||||
let fee: u64 = 1_000_000;
|
||||
let blind = secp::random_secret();
|
||||
let input_commit = secp::commit(value, &blind)?;
|
||||
|
||||
let server_key = secp::random_secret();
|
||||
let hop_excess = secp::random_secret();
|
||||
let proof = proof(value, fee, &blind, &hop_excess);
|
||||
let hop = new_hop(&server_key, &hop_excess, fee, Some(proof));
|
||||
|
||||
let onion = test_util::create_onion(&input_commit, &vec![hop])?;
|
||||
let comsig = ComSignature::sign(value, &blind, &onion.serialize()?)?;
|
||||
|
||||
let (server, _node) = new_server(&server_key, &vec![&input_commit]);
|
||||
let result = server.swap(&onion, &comsig);
|
||||
assert_eq!(
|
||||
Err(SwapError::FeeTooLow {
|
||||
minimum_fee: 12_500_000,
|
||||
actual_fee: fee
|
||||
}),
|
||||
result
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue