diff --git a/core/src/reservation.rs b/core/src/reservation.rs index 7bd612ebd9e..9c4f4184d2b 100644 --- a/core/src/reservation.rs +++ b/core/src/reservation.rs @@ -201,14 +201,20 @@ impl GasReserver { /// 2. Reservation was "unreserved", so in [`GasReservationState::Removed`] state. /// 3. Reservation was marked used. pub fn unreserve(&mut self, id: ReservationId) -> Result { + // Docs error case #1. let state = self .states .get(&id) .ok_or(ReservationError::InvalidReservationId)?; - if let GasReservationState::Exists { used: true, .. } - | GasReservationState::Created { used: true, .. } = state - { + if matches!( + state, + // Docs error case #2. + GasReservationState::Removed { .. } | + // Docs error case #3. + GasReservationState::Exists { used: true, .. } | + GasReservationState::Created { used: true, .. } + ) { return Err(ReservationError::InvalidReservationId); } @@ -221,9 +227,7 @@ impl GasReserver { amount } GasReservationState::Created { amount, .. } => amount, - GasReservationState::Removed { .. } => { - return Err(ReservationError::InvalidReservationId); - } + GasReservationState::Removed { .. } => unreachable!("Checked above"), }; Ok(amount) @@ -485,4 +489,30 @@ mod tests { Err(ReservationError::InvalidReservationId) ); } + + #[test] + fn unreserving_unreserved() { + let id = ReservationId::from([0xff; 32]); + let slot = GasReservationSlot { + amount: 1, + start: 2, + finish: 3, + }; + + let mut map = GasReservationMap::new(); + map.insert(id, slot.clone()); + + let mut reserver = GasReserver::new(&Default::default(), map, 256); + + let amount = reserver.unreserve(id).expect("Shouldn't fail"); + assert_eq!(amount, slot.amount); + + assert!(reserver.unreserve(id).is_err()); + assert_eq!( + reserver.states().get(&id).cloned(), + Some(GasReservationState::Removed { + expiration: slot.finish + }) + ); + } } diff --git a/utils/runtime-fuzzer/fuzz_corpus/aa91f1d5873e3fa7045ceeef9e26448e71f82482 b/utils/runtime-fuzzer/fuzz_corpus/aa91f1d5873e3fa7045ceeef9e26448e71f82482 new file mode 100644 index 00000000000..dc69e788bde Binary files /dev/null and b/utils/runtime-fuzzer/fuzz_corpus/aa91f1d5873e3fa7045ceeef9e26448e71f82482 differ diff --git a/utils/runtime-fuzzer/src/tests.rs b/utils/runtime-fuzzer/src/tests.rs index 7750759d514..b8bf8a978dc 100644 --- a/utils/runtime-fuzzer/src/tests.rs +++ b/utils/runtime-fuzzer/src/tests.rs @@ -40,6 +40,14 @@ fn test_corpus_c6e2a597aebabecc9bbb11eefdaa4dd8a6770188() { assert!(run_impl(FuzzerInput::new(input)).is_ok()); } +#[test] +fn test_corpus_aa91f1d5873e3fa7045ceeef9e26448e71f82482() { + gear_utils::init_default_logger(); + + let input = include_bytes!("../fuzz_corpus/aa91f1d5873e3fa7045ceeef9e26448e71f82482"); + assert!(run_impl(FuzzerInput::new(input)).is_ok()); +} + proptest! { #![proptest_config(ProptestConfig::with_cases(10))] #[test]