From 59e8abf04817bb1a7470234c38bf251bc9d973ae Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 15:18:03 -0800 Subject: [PATCH 01/10] Modify fee calculation to use higher int size --- cmd/crates/soroban-rpc/src/txn.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 35b0c719..5604581e 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -315,13 +315,19 @@ pub fn assemble( // update the fees of the actual transaction to meet the minimum resource fees. let classic_transaction_fees = crate::DEFAULT_TRANSACTION_FEES; - // Pad the fees up by 15% for a bit of wiggle room. - tx.fee = (tx.fee.max( - classic_transaction_fees - + u32::try_from(simulation.min_resource_fee) - .map_err(|_| Error::LargeFee(simulation.min_resource_fee))?, - ) * 115) - / 100; + + // Pad the fees up by 15% for a bit of wiggle room + let padded_fee = u64::try_from( + tx.fee.max( + classic_transaction_fees + + u32::try_from(simulation.min_resource_fee) + .map_err(|_| Error::LargeFee(simulation.min_resource_fee))?, + ), + ) + .map_err(|_| Error::LargeFee(simulation.min_resource_fee)) + / 100 + * 115; + tx.fee(u32::try_from(padded_fee).map_err(|_| Error::LargeFee(padded_fee))); tx.operations = vec![op].try_into()?; tx.ext = TransactionExt::V1(transaction_data); From 783dc98d66ed278140181453824a27fb3918f573 Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 15:20:44 -0800 Subject: [PATCH 02/10] Second u64 cast cannot fail --- cmd/crates/soroban-rpc/src/txn.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 5604581e..313caf80 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -317,17 +317,15 @@ pub fn assemble( let classic_transaction_fees = crate::DEFAULT_TRANSACTION_FEES; // Pad the fees up by 15% for a bit of wiggle room - let padded_fee = u64::try_from( + let padded_fee = u64::from( tx.fee.max( classic_transaction_fees + u32::try_from(simulation.min_resource_fee) .map_err(|_| Error::LargeFee(simulation.min_resource_fee))?, ), - ) - .map_err(|_| Error::LargeFee(simulation.min_resource_fee)) - / 100 + ) / 100 * 115; - tx.fee(u32::try_from(padded_fee).map_err(|_| Error::LargeFee(padded_fee))); + tx.fee = u32::try_from(padded_fee).map_err(|_| Error::LargeFee(padded_fee))?; tx.operations = vec![op].try_into()?; tx.ext = TransactionExt::V1(transaction_data); From 9102902c6ed77f636ff0373d6b5eae7144a28edf Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 16:18:28 -0800 Subject: [PATCH 03/10] Add tests for various overflow cases --- cmd/crates/soroban-rpc/src/txn.rs | 73 ++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 313caf80..6efbf2c0 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -323,8 +323,8 @@ pub fn assemble( + u32::try_from(simulation.min_resource_fee) .map_err(|_| Error::LargeFee(simulation.min_resource_fee))?, ), - ) / 100 - * 115; + ) * 115 + / 100; tx.fee = u32::try_from(padded_fee).map_err(|_| Error::LargeFee(padded_fee))?; tx.operations = vec![op].try_into()?; @@ -725,4 +725,73 @@ mod tests { r => panic!("expected UnexpectedSimulateTransactionResultSize error, got: {r:#?}"), } } + + #[test] + fn test_assemble_transaction_overflow_behavior() { + // Test three separate cases: + // + // 1. Given a near-max (U32_MAX) resource fee, ensure the "wiggle room" + // doesn't cause an overflow due to correct math order. + // (Specifically, do U32_MAX - 15% - 100 - 1, so the final fee is + // U32_MAX-1.) + // + // 3. Given a near-max (U32_MAX) resource fee that will ONLY exceed + // U32_MAX *with* the wiggle room, ensure the overflow is caught + // with an error rather than silently ignored. + // + // 2. Given a large resource fee that WILL exceed on its own, ensure + // the overflow is caught with an error rather than silently + // ignored. + // + let txn = single_contract_fn_transaction(); + let mut response = simulation_response(); + + // sanity check so these can be adjusted if the above helper changes + assert_eq!(txn.fee, 100, "modified txn.fee: update the math below"); + + // 1: wiggle room math overflows but result fits + let mut resource_fee = ((u32::MAX as f64) * 0.85).floor() as u64 - 100 - 1; + assert_eq!(resource_fee, 3650722099); + response.min_resource_fee = resource_fee; + + match assemble(&txn, &response) { + Ok(atxn) => { + let expected = (((resource_fee + 100) as f64) * 1.15) as u32; + assert_eq!(atxn.fee, expected); + } + r => { + panic!("expected success, got: {r:#?}") + } + } + + // 2: combo works but wiggle room overflows + resource_fee = ((u32::MAX as f64) * 0.90).floor() as u64; + assert_eq!(resource_fee, 3865470565); + response.min_resource_fee = resource_fee; + + match assemble(&txn, &response) { + Err(Error::LargeFee(fee)) => { + let expected = (((resource_fee + 100) as f64) * 1.15).floor() as u64; + assert_eq!(expected, fee, "expected {} != {} actual", expected, fee); + } + r => { + panic!("expected LargeFee error, got: {r:#?}") + } + } + + // 3: combo overflows + resource_fee = (u32::MAX - 100) as u64; + assert_eq!(resource_fee, 4294967195); + response.min_resource_fee = resource_fee; + + match assemble(&txn, &response) { + Err(Error::LargeFee(fee)) => { + let expected = (((resource_fee + 100) as f64) * 1.15).floor() as u64; + assert_eq!(expected, fee, "expected {} != {} actual", expected, fee); + } + r => { + panic!("expected LargeFee error, got: {r:#?}") + } + } + } } From b5333ae5f2bc528d54f856ae17a065b5eaa11fec Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 16:29:58 -0800 Subject: [PATCH 04/10] Appeasing clippy :pray: --- cmd/crates/soroban-rpc/src/txn.rs | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 6efbf2c0..2cec34d5 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -750,48 +750,42 @@ mod tests { assert_eq!(txn.fee, 100, "modified txn.fee: update the math below"); // 1: wiggle room math overflows but result fits - let mut resource_fee = ((u32::MAX as f64) * 0.85).floor() as u64 - 100 - 1; - assert_eq!(resource_fee, 3650722099); + let mut resource_fee = (u32::MAX as u64 * 85 / 100) - 100 - 1; + assert_eq!(resource_fee, 3_650_722_099); response.min_resource_fee = resource_fee; match assemble(&txn, &response) { - Ok(atxn) => { - let expected = (((resource_fee + 100) as f64) * 1.15) as u32; - assert_eq!(atxn.fee, expected); - } - r => { - panic!("expected success, got: {r:#?}") + Ok(asstxn) => { + let expected = u32::from(resource_fee + 100 * 115 / 100); + assert_eq!(asstxn.fee, expected); } + r => panic!("expected success, got: {r:#?}"), } // 2: combo works but wiggle room overflows - resource_fee = ((u32::MAX as f64) * 0.90).floor() as u64; - assert_eq!(resource_fee, 3865470565); + resource_fee = u32::MAX as u64 * 90 / 100; + assert_eq!(resource_fee, 3_865_470_565); response.min_resource_fee = resource_fee; match assemble(&txn, &response) { Err(Error::LargeFee(fee)) => { - let expected = (((resource_fee + 100) as f64) * 1.15).floor() as u64; + let expected = resource_fee + 100 * 115 / 100; assert_eq!(expected, fee, "expected {} != {} actual", expected, fee); } - r => { - panic!("expected LargeFee error, got: {r:#?}") - } + r => panic!("expected LargeFee error, got: {r:#?}"), } // 3: combo overflows resource_fee = (u32::MAX - 100) as u64; - assert_eq!(resource_fee, 4294967195); + assert_eq!(resource_fee, 4_294_967_195); response.min_resource_fee = resource_fee; match assemble(&txn, &response) { Err(Error::LargeFee(fee)) => { - let expected = (((resource_fee + 100) as f64) * 1.15).floor() as u64; + let expected = resource_fee + 100 * 115 / 100; assert_eq!(expected, fee, "expected {} != {} actual", expected, fee); } - r => { - panic!("expected LargeFee error, got: {r:#?}") - } + r => panic!("expected LargeFee error, got: {r:#?}"), } } } From f5a7f8af00e7fdd8e83054a310bca622c7f5417d Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 17:23:06 -0800 Subject: [PATCH 05/10] Simplify behavior and add another overflow check --- cmd/crates/soroban-rpc/src/txn.rs | 49 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 2cec34d5..5db069fe 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -313,19 +313,17 @@ pub fn assemble( } } - // update the fees of the actual transaction to meet the minimum resource fees. - let classic_transaction_fees = crate::DEFAULT_TRANSACTION_FEES; - - // Pad the fees up by 15% for a bit of wiggle room - let padded_fee = u64::from( - tx.fee.max( - classic_transaction_fees - + u32::try_from(simulation.min_resource_fee) - .map_err(|_| Error::LargeFee(simulation.min_resource_fee))?, - ), - ) * 115 - / 100; - tx.fee = u32::try_from(padded_fee).map_err(|_| Error::LargeFee(padded_fee))?; + // Update transaction fees to meet the minimum resource fees. + let classic_tx_fee = crate::DEFAULT_TRANSACTION_FEES as u64; + + // Choose larger of existing fee or inclusion + resource fee. + let base_tx_fee = tx.fee.max( + u32::try_from(classic_tx_fee + simulation.min_resource_fee) + .map_err(|_| Error::LargeFee(simulation.min_resource_fee + classic_tx_fee))?, + ); + + // Pad the total fee by up to 15% for a bit of wiggle room. + tx.fee = ((base_tx_fee as u64) * 115 / 100).min(u32::MAX as u64) as u32; tx.operations = vec![op].try_into()?; tx.ext = TransactionExt::V1(transaction_data); @@ -736,8 +734,8 @@ mod tests { // U32_MAX-1.) // // 3. Given a near-max (U32_MAX) resource fee that will ONLY exceed - // U32_MAX *with* the wiggle room, ensure the overflow is caught - // with an error rather than silently ignored. + // U32_MAX *with* the wiggle room, ensure the overflow is ignored + // and we just use the max that's possible. // // 2. Given a large resource fee that WILL exceed on its own, ensure // the overflow is caught with an error rather than silently @@ -756,34 +754,33 @@ mod tests { match assemble(&txn, &response) { Ok(asstxn) => { - let expected = u32::from(resource_fee + 100 * 115 / 100); + let expected = ((resource_fee + 100) * 115 / 100) as u32; assert_eq!(asstxn.fee, expected); } r => panic!("expected success, got: {r:#?}"), } - // 2: combo works but wiggle room overflows + // 2: combo works but wiggle room overflows, should cap resource_fee = u32::MAX as u64 * 90 / 100; assert_eq!(resource_fee, 3_865_470_565); response.min_resource_fee = resource_fee; match assemble(&txn, &response) { - Err(Error::LargeFee(fee)) => { - let expected = resource_fee + 100 * 115 / 100; - assert_eq!(expected, fee, "expected {} != {} actual", expected, fee); + Ok(asstxn) => { + assert_eq!(asstxn.fee, u32::MAX); } - r => panic!("expected LargeFee error, got: {r:#?}"), + r => panic!("expected success, got: {r:#?}"), } - // 3: combo overflows - resource_fee = (u32::MAX - 100) as u64; - assert_eq!(resource_fee, 4_294_967_195); + // 3: combo overflows, should throw + resource_fee = u32::MAX as u64; + assert_eq!(resource_fee, 4_294_967_295); response.min_resource_fee = resource_fee; match assemble(&txn, &response) { Err(Error::LargeFee(fee)) => { - let expected = resource_fee + 100 * 115 / 100; - assert_eq!(expected, fee, "expected {} != {} actual", expected, fee); + let expected = resource_fee + 100; + assert_eq!(expected, fee, "expected {expected} != {fee} actual") } r => panic!("expected LargeFee error, got: {r:#?}"), } From 14c2c44c95b22e1a2aa159d6ee0a2922908e4962 Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 17:26:49 -0800 Subject: [PATCH 06/10] Clarify bounds --- cmd/crates/soroban-rpc/src/txn.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 5db069fe..87f9b02d 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -320,10 +320,10 @@ pub fn assemble( let base_tx_fee = tx.fee.max( u32::try_from(classic_tx_fee + simulation.min_resource_fee) .map_err(|_| Error::LargeFee(simulation.min_resource_fee + classic_tx_fee))?, - ); + ) as u64; // invariant: base_tx_fee <= u32::MAX // Pad the total fee by up to 15% for a bit of wiggle room. - tx.fee = ((base_tx_fee as u64) * 115 / 100).min(u32::MAX as u64) as u32; + tx.fee = (base_tx_fee * 115 / 100).min(u32::MAX as u64) as u32; tx.operations = vec![op].try_into()?; tx.ext = TransactionExt::V1(transaction_data); From 4de7feec7bb825a53ac45295ee19f3ea629cd7da Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 17:35:03 -0800 Subject: [PATCH 07/10] Fixup comments, appease clippy :pray: --- cmd/crates/soroban-rpc/src/txn.rs | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 87f9b02d..0b6c93a4 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -726,6 +726,7 @@ mod tests { #[test] fn test_assemble_transaction_overflow_behavior() { + // // Test three separate cases: // // 1. Given a near-max (U32_MAX) resource fee, ensure the "wiggle room" @@ -733,13 +734,12 @@ mod tests { // (Specifically, do U32_MAX - 15% - 100 - 1, so the final fee is // U32_MAX-1.) // - // 3. Given a near-max (U32_MAX) resource fee that will ONLY exceed - // U32_MAX *with* the wiggle room, ensure the overflow is ignored - // and we just use the max that's possible. + // 2. Given a large resource fee that WILL exceed on its own with the + // inclusion fee, ensure the overflow is caught with an error rather + // than silently ignored. // - // 2. Given a large resource fee that WILL exceed on its own, ensure - // the overflow is caught with an error rather than silently - // ignored. + // 3. Given a max resource fee that exceeds U32_MAX *only with* wiggle + // room, ensure the overflow is ignored and we cap on the max. // let txn = single_contract_fn_transaction(); let mut response = simulation_response(); @@ -760,29 +760,29 @@ mod tests { r => panic!("expected success, got: {r:#?}"), } - // 2: combo works but wiggle room overflows, should cap - resource_fee = u32::MAX as u64 * 90 / 100; - assert_eq!(resource_fee, 3_865_470_565); + // 2: combo overflows, should throw + resource_fee = u32::MAX as u64; + assert_eq!(resource_fee, 4_294_967_295); response.min_resource_fee = resource_fee; match assemble(&txn, &response) { - Ok(asstxn) => { - assert_eq!(asstxn.fee, u32::MAX); + Err(Error::LargeFee(fee)) => { + let expected = resource_fee + 100; + assert_eq!(expected, fee, "expected {expected} != {fee} actual"); } - r => panic!("expected success, got: {r:#?}"), + r => panic!("expected LargeFee error, got: {r:#?}"), } - // 3: combo overflows, should throw - resource_fee = u32::MAX as u64; - assert_eq!(resource_fee, 4_294_967_295); + // 2: combo works but wiggle room overflows, should cap + resource_fee = u32::MAX as u64 * 90 / 100; + assert_eq!(resource_fee, 3_865_470_565); response.min_resource_fee = resource_fee; match assemble(&txn, &response) { - Err(Error::LargeFee(fee)) => { - let expected = resource_fee + 100; - assert_eq!(expected, fee, "expected {expected} != {fee} actual") + Ok(asstxn) => { + assert_eq!(asstxn.fee, u32::MAX); } - r => panic!("expected LargeFee error, got: {r:#?}"), + r => panic!("expected success, got: {r:#?}"), } } } From d2a57503f52f6d67405d2d0c529c385363581695 Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 17:45:39 -0800 Subject: [PATCH 08/10] More appeasement because clippy is annoying --- cmd/crates/soroban-rpc/src/txn.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 0b6c93a4..7eaeec59 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -314,16 +314,23 @@ pub fn assemble( } // Update transaction fees to meet the minimum resource fees. - let classic_tx_fee = crate::DEFAULT_TRANSACTION_FEES as u64; + let classic_tx_fee: u64 = crate::DEFAULT_TRANSACTION_FEES.into(); // Choose larger of existing fee or inclusion + resource fee. - let base_tx_fee = tx.fee.max( - u32::try_from(classic_tx_fee + simulation.min_resource_fee) - .map_err(|_| Error::LargeFee(simulation.min_resource_fee + classic_tx_fee))?, - ) as u64; // invariant: base_tx_fee <= u32::MAX + let base_tx_fee = u64::from( + tx.fee.max( + u32::try_from(classic_tx_fee + simulation.min_resource_fee) + .map_err(|_| Error::LargeFee(simulation.min_resource_fee + classic_tx_fee))?, + ), + ); // invariant: base_tx_fee <= u32::MAX // Pad the total fee by up to 15% for a bit of wiggle room. - tx.fee = (base_tx_fee * 115 / 100).min(u32::MAX as u64) as u32; + // + // We know for a fact because of the .min call that we will not exceed + // U32_MAX, but we can't get clippy to shut the fuck up for this single + // line, so we have a redundant error check anyway. + tx.fee = u32::try_from((base_tx_fee * 115 / 100).min(u64::from(u32::MAX))) + .map_err(|_| Error::LargeFee(base_tx_fee))?; tx.operations = vec![op].try_into()?; tx.ext = TransactionExt::V1(transaction_data); @@ -748,20 +755,21 @@ mod tests { assert_eq!(txn.fee, 100, "modified txn.fee: update the math below"); // 1: wiggle room math overflows but result fits - let mut resource_fee = (u32::MAX as u64 * 85 / 100) - 100 - 1; + let mut resource_fee = (u64::from(u32::MAX) * 85 / 100) - 100 - 1; assert_eq!(resource_fee, 3_650_722_099); response.min_resource_fee = resource_fee; match assemble(&txn, &response) { Ok(asstxn) => { - let expected = ((resource_fee + 100) * 115 / 100) as u32; - assert_eq!(asstxn.fee, expected); + let expected = (resource_fee + 100) * 115 / 100; + assert!(u32::try_from(expected).is_ok()); + assert_eq!(asstxn.fee, expected as u32); } r => panic!("expected success, got: {r:#?}"), } // 2: combo overflows, should throw - resource_fee = u32::MAX as u64; + resource_fee = u64::from(u32::MAX); assert_eq!(resource_fee, 4_294_967_295); response.min_resource_fee = resource_fee; @@ -774,7 +782,7 @@ mod tests { } // 2: combo works but wiggle room overflows, should cap - resource_fee = u32::MAX as u64 * 90 / 100; + resource_fee = u64::from(u32::MAX) * 90 / 100; assert_eq!(resource_fee, 3_865_470_565); response.min_resource_fee = resource_fee; From 650bf96724262b457ff0733c93e446ffff99745f Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 17:47:43 -0800 Subject: [PATCH 09/10] Use .into() over .from() for readability --- cmd/crates/soroban-rpc/src/txn.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 7eaeec59..29ba11c8 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -317,16 +317,17 @@ pub fn assemble( let classic_tx_fee: u64 = crate::DEFAULT_TRANSACTION_FEES.into(); // Choose larger of existing fee or inclusion + resource fee. - let base_tx_fee = u64::from( - tx.fee.max( + let base_tx_fee: u64 = tx + .fee + .max( u32::try_from(classic_tx_fee + simulation.min_resource_fee) .map_err(|_| Error::LargeFee(simulation.min_resource_fee + classic_tx_fee))?, - ), - ); // invariant: base_tx_fee <= u32::MAX + ) + .into(); // invariant: base_tx_fee <= u32::MAX // Pad the total fee by up to 15% for a bit of wiggle room. // - // We know for a fact because of the .min call that we will not exceed + // We know for a fact because of the .min() call that we will not exceed // U32_MAX, but we can't get clippy to shut the fuck up for this single // line, so we have a redundant error check anyway. tx.fee = u32::try_from((base_tx_fee * 115 / 100).min(u64::from(u32::MAX))) From 459c42f2ae7d9107a5218552367c0c7a73718a08 Mon Sep 17 00:00:00 2001 From: George Kudrayvtsev Date: Tue, 20 Feb 2024 17:54:03 -0800 Subject: [PATCH 10/10] It's not a warning even in tests? Fuck off --- cmd/crates/soroban-rpc/src/txn.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/crates/soroban-rpc/src/txn.rs b/cmd/crates/soroban-rpc/src/txn.rs index 29ba11c8..d713637b 100644 --- a/cmd/crates/soroban-rpc/src/txn.rs +++ b/cmd/crates/soroban-rpc/src/txn.rs @@ -763,8 +763,7 @@ mod tests { match assemble(&txn, &response) { Ok(asstxn) => { let expected = (resource_fee + 100) * 115 / 100; - assert!(u32::try_from(expected).is_ok()); - assert_eq!(asstxn.fee, expected as u32); + assert_eq!(asstxn.fee, u32::try_from(expected).unwrap()); } r => panic!("expected success, got: {r:#?}"), }