overflow.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. use std::time::Duration;
  2. use anyhow::{bail, Result};
  3. use cdk::amount::SplitTarget;
  4. use cdk::dhke::construct_proofs;
  5. use cdk::nuts::{CurrencyUnit, MintQuoteState, PreMintSecrets, SwapRequest};
  6. use cdk::Amount;
  7. use cdk::HttpClient;
  8. use cdk_integration_tests::{create_backends_fake_wallet, start_mint, MINT_URL};
  9. use tokio::time::sleep;
  10. /// This attempts to swap for more outputs then inputs.
  11. /// This will work if the mint does not check for outputs amounts overflowing
  12. async fn attempt_to_swap_by_overflowing() -> Result<()> {
  13. let wallet_client = HttpClient::new();
  14. let mint_keys = wallet_client.get_mint_keys(MINT_URL.parse()?).await?;
  15. let mint_keys = mint_keys.first().unwrap();
  16. let keyset_id = mint_keys.id;
  17. let mint_quote = wallet_client
  18. .post_mint_quote(MINT_URL.parse()?, 100.into(), CurrencyUnit::Sat)
  19. .await?;
  20. loop {
  21. let status = wallet_client
  22. .get_mint_quote_status(MINT_URL.parse()?, &mint_quote.quote)
  23. .await?;
  24. if status.state == MintQuoteState::Paid {
  25. break;
  26. }
  27. println!("{:?}", status);
  28. sleep(Duration::from_secs(2)).await;
  29. }
  30. let premint_secrets = PreMintSecrets::random(keyset_id, 1.into(), &SplitTarget::default())?;
  31. let mint_response = wallet_client
  32. .post_mint(
  33. MINT_URL.parse()?,
  34. &mint_quote.quote,
  35. premint_secrets.clone(),
  36. )
  37. .await?;
  38. let pre_swap_proofs = construct_proofs(
  39. mint_response.signatures,
  40. premint_secrets.rs(),
  41. premint_secrets.secrets(),
  42. &mint_keys.clone().keys,
  43. )?;
  44. // Construct messages that will overflow
  45. let amount = 2_u64.pow(63);
  46. let pre_mint_amount =
  47. PreMintSecrets::random(keyset_id, amount.into(), &SplitTarget::default())?;
  48. let pre_mint_amount_two =
  49. PreMintSecrets::random(keyset_id, amount.into(), &SplitTarget::default())?;
  50. let mut pre_mint = PreMintSecrets::random(keyset_id, 1.into(), &SplitTarget::default())?;
  51. pre_mint.combine(pre_mint_amount);
  52. pre_mint.combine(pre_mint_amount_two);
  53. let swap_request = SwapRequest::new(pre_swap_proofs.clone(), pre_mint.blinded_messages());
  54. let swap_response = match wallet_client
  55. .post_swap(MINT_URL.parse()?, swap_request)
  56. .await
  57. {
  58. Ok(res) => res,
  59. // In the context of this test an error response here is good.
  60. // It means the mint does not allow us to swap for more then we should by overflowing
  61. Err(_err) => return Ok(()),
  62. };
  63. let post_swap_proofs = construct_proofs(
  64. swap_response.signatures,
  65. pre_mint.rs(),
  66. pre_mint.secrets(),
  67. &mint_keys.clone().keys,
  68. )?;
  69. println!(
  70. "Pre swap amount: {:?}",
  71. Amount::try_sum(pre_swap_proofs.iter().map(|p| p.amount)).expect("Amount overflowed")
  72. );
  73. println!(
  74. "Post swap amount: {:?}",
  75. Amount::try_sum(post_swap_proofs.iter().map(|p| p.amount)).expect("Amount Overflowed")
  76. );
  77. println!(
  78. "Pre swap amounts: {:?}",
  79. pre_swap_proofs
  80. .iter()
  81. .map(|p| p.amount)
  82. .collect::<Vec<Amount>>()
  83. );
  84. println!(
  85. "Post swap amounts: {:?}",
  86. post_swap_proofs
  87. .iter()
  88. .map(|p| p.amount)
  89. .collect::<Vec<Amount>>()
  90. );
  91. bail!("Should not have been able to swap")
  92. }
  93. #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
  94. pub async fn test_overflow() -> Result<()> {
  95. tokio::spawn(async move {
  96. let ln_backends = create_backends_fake_wallet();
  97. start_mint(ln_backends).await.expect("Could not start mint")
  98. });
  99. // Wait for mint server to start
  100. tokio::time::sleep(Duration::from_millis(500)).await;
  101. let result = attempt_to_swap_by_overflowing().await;
  102. assert!(result.is_ok());
  103. Ok(())
  104. }