#![cfg(test)]
use super::*;
use crate::mock::*;
use frame_support::{
assert_err, assert_noop, assert_ok, assert_storage_noop, bounded_vec,
traits::{Bounded, BoundedInline, Hash as PreimageHash},
StorageNoopGuard,
};
use pallet_balances::Error as BalancesError;
use sp_core::{blake2_256, H256};
pub fn make_bounded_values() -> (Bounded<Vec<u8>>, Bounded<Vec<u8>>, Bounded<Vec<u8>>) {
let data: BoundedInline = bounded_vec![1];
let inline = Bounded::<Vec<u8>>::Inline(data);
let data = vec![1, 2];
let hash: H256 = blake2_256(&data[..]).into();
let len = data.len() as u32;
let lookup = Bounded::<Vec<u8>>::unrequested(hash, len);
let data = vec![1, 2, 3];
let hash: H256 = blake2_256(&data[..]).into();
let legacy = Bounded::<Vec<u8>>::Legacy { hash, dummy: Default::default() };
(inline, lookup, legacy)
}
#[test]
fn user_note_preimage_works() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_eq!(Balances::reserved_balance(2), 3);
assert_eq!(Balances::free_balance(2), 97);
let h = hashed([1]);
assert!(Preimage::have_preimage(&h));
assert_eq!(Preimage::get_preimage(&h), Some(vec![1]));
assert_noop!(
Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]),
Error::<Test>::AlreadyNoted
);
assert_noop!(
Preimage::note_preimage(RuntimeOrigin::signed(0), vec![2]),
BalancesError::<Test>::InsufficientBalance
);
});
}
#[test]
fn manager_note_preimage_works() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
assert_eq!(Balances::reserved_balance(1), 0);
assert_eq!(Balances::free_balance(1), 100);
let h = hashed([1]);
assert!(Preimage::have_preimage(&h));
assert_eq!(Preimage::get_preimage(&h), Some(vec![1]));
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
});
}
#[test]
fn user_unnote_preimage_works() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_noop!(
Preimage::unnote_preimage(RuntimeOrigin::signed(3), hashed([1])),
Error::<Test>::NotAuthorized
);
assert_noop!(
Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([2])),
Error::<Test>::NotNoted
);
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
assert_noop!(
Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])),
Error::<Test>::NotNoted
);
let h = hashed([1]);
assert!(!Preimage::have_preimage(&h));
assert_eq!(Preimage::get_preimage(&h), None);
});
}
#[test]
fn manager_unnote_preimage_works() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_noop!(
Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])),
Error::<Test>::NotNoted
);
let h = hashed([1]);
assert!(!Preimage::have_preimage(&h));
assert_eq!(Preimage::get_preimage(&h), None);
});
}
#[test]
fn manager_unnote_user_preimage_works() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_noop!(
Preimage::unnote_preimage(RuntimeOrigin::signed(3), hashed([1])),
Error::<Test>::NotAuthorized
);
assert_noop!(
Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([2])),
Error::<Test>::NotNoted
);
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])));
let h = hashed([1]);
assert!(!Preimage::have_preimage(&h));
assert_eq!(Preimage::get_preimage(&h), None);
});
}
#[test]
fn requested_then_noted_preimage_cannot_be_unnoted() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])));
let h = hashed([1]);
assert!(Preimage::have_preimage(&h));
assert_eq!(Preimage::get_preimage(&h), Some(vec![1]));
assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert!(!Preimage::have_preimage(&hashed([1])));
});
}
#[test]
fn request_note_order_makes_no_difference() {
let one_way = new_test_ext().execute_with(|| {
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
(
StatusFor::<Test>::iter().collect::<Vec<_>>(),
PreimageFor::<Test>::iter().collect::<Vec<_>>(),
)
});
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
let other_way = (
StatusFor::<Test>::iter().collect::<Vec<_>>(),
PreimageFor::<Test>::iter().collect::<Vec<_>>(),
);
assert_eq!(one_way, other_way);
});
}
#[test]
fn requested_then_user_noted_preimage_is_free() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_eq!(Balances::reserved_balance(2), 0);
assert_eq!(Balances::free_balance(2), 100);
let h = hashed([1]);
assert!(Preimage::have_preimage(&h));
assert_eq!(Preimage::get_preimage(&h), Some(vec![1]));
});
}
#[test]
fn request_user_note_order_makes_no_difference() {
let one_way = new_test_ext().execute_with(|| {
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
(
StatusFor::<Test>::iter().collect::<Vec<_>>(),
PreimageFor::<Test>::iter().collect::<Vec<_>>(),
)
});
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
let other_way = (
StatusFor::<Test>::iter().collect::<Vec<_>>(),
PreimageFor::<Test>::iter().collect::<Vec<_>>(),
);
assert_eq!(one_way, other_way);
});
}
#[test]
fn unrequest_preimage_works() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_noop!(
Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([2])),
Error::<Test>::NotRequested
);
assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert!(Preimage::have_preimage(&hashed([1])));
assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_noop!(
Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])),
Error::<Test>::NotRequested
);
});
}
#[test]
fn user_noted_then_requested_preimage_is_refunded_once_only() {
new_test_ext().execute_with(|| {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1; 3]));
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])));
assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
assert_eq!(Balances::reserved_balance(2), 5);
assert_eq!(Balances::free_balance(2), 95);
});
}
#[test]
fn noted_preimage_use_correct_map() {
new_test_ext().execute_with(|| {
for i in 0..7 {
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; 128 << (i * 2)]));
}
assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; MAX_SIZE as usize]));
assert_eq!(PreimageFor::<Test>::iter().count(), 8);
assert_eq!(StatusFor::<Test>::iter().count(), 8);
for i in 0..7 {
assert_ok!(Preimage::unnote_preimage(
RuntimeOrigin::signed(1),
hashed(vec![0; 128 << (i * 2)])
));
}
assert_eq!(PreimageFor::<Test>::iter().count(), 1);
assert_ok!(Preimage::unnote_preimage(
RuntimeOrigin::signed(1),
hashed(vec![0; MAX_SIZE as usize])
));
assert_eq!(PreimageFor::<Test>::iter().count(), 0);
assert_eq!(StatusFor::<Test>::iter().count(), 0);
});
}
#[test]
fn query_and_store_preimage_workflow() {
new_test_ext().execute_with(|| {
let _guard = StorageNoopGuard::default();
let data: Vec<u8> = vec![1; 512];
let encoded = data.encode();
let bound = Preimage::bound(data.clone()).unwrap();
let (len, hash) = (bound.len().unwrap(), bound.hash());
assert_eq!(hash, blake2_256(&encoded).into());
assert_eq!(bound.len(), Some(len));
assert!(bound.lookup_needed(), "Should not be Inlined");
assert_eq!(bound.lookup_len(), Some(len));
assert!(Preimage::is_requested(&hash));
assert!(<Preimage as QueryPreimage>::have(&bound));
assert_eq!(Preimage::len(&hash), Some(len));
assert_eq!(Preimage::fetch(&hash, Some(len)).unwrap(), encoded);
assert_eq!(Preimage::fetch(&hash, None).unwrap(), encoded);
assert_err!(Preimage::fetch(&hash, Some(0)), DispatchError::Unavailable);
assert_eq!(Preimage::peek::<Vec<u8>>(&bound).unwrap(), (data.clone(), Some(len)));
assert_eq!(Preimage::pick::<Vec<u8>>(hash, len), bound);
Preimage::request(&hash);
assert!(matches!(
StatusFor::<Test>::get(&hash).unwrap(),
RequestStatus::Requested { count: 3, .. }
));
assert_eq!(Preimage::realize::<Vec<u8>>(&bound).unwrap(), (data.clone(), Some(len)));
assert!(matches!(
StatusFor::<Test>::get(&hash).unwrap(),
RequestStatus::Requested { count: 2, .. }
));
Preimage::drop(&bound);
assert!(matches!(
StatusFor::<Test>::get(&hash).unwrap(),
RequestStatus::Requested { count: 1, .. }
));
assert!(<Preimage as QueryPreimage>::have(&bound));
Preimage::unnote(&hash);
assert!(!<Preimage as QueryPreimage>::have(&bound));
assert_err!(Preimage::fetch(&hash, Some(len)), DispatchError::Unavailable);
assert!(!Preimage::is_requested(&hash));
});
}
#[test]
fn query_preimage_request_works() {
new_test_ext().execute_with(|| {
let _guard = StorageNoopGuard::default();
let data: Vec<u8> = vec![1; 10];
let hash: PreimageHash = blake2_256(&data[..]).into();
<Preimage as QueryPreimage>::request(&hash);
assert!(<Preimage as QueryPreimage>::is_requested(&hash));
assert!(<Preimage as QueryPreimage>::len(&hash).is_none());
assert_noop!(<Preimage as QueryPreimage>::fetch(&hash, None), DispatchError::Unavailable);
<Preimage as QueryPreimage>::request(&hash);
assert!(<Preimage as QueryPreimage>::is_requested(&hash));
assert!(<Preimage as QueryPreimage>::len(&hash).is_none());
assert_noop!(<Preimage as QueryPreimage>::fetch(&hash, None), DispatchError::Unavailable);
assert_eq!(StatusFor::<Test>::iter().count(), 1);
<Preimage as QueryPreimage>::unrequest(&hash);
assert!(<Preimage as QueryPreimage>::is_requested(&hash));
<Preimage as QueryPreimage>::unrequest(&hash);
assert!(!<Preimage as QueryPreimage>::is_requested(&hash));
assert_eq!(StatusFor::<Test>::iter().count(), 0);
});
}
#[test]
fn query_preimage_hold_and_drop_work() {
new_test_ext().execute_with(|| {
let _guard = StorageNoopGuard::default();
let (inline, lookup, legacy) = make_bounded_values();
assert_storage_noop!(<Preimage as QueryPreimage>::hold(&inline));
<Preimage as QueryPreimage>::hold(&lookup);
assert!(<Preimage as QueryPreimage>::is_requested(&lookup.hash()));
<Preimage as QueryPreimage>::hold(&legacy);
assert!(<Preimage as QueryPreimage>::is_requested(&legacy.hash()));
assert_eq!(StatusFor::<Test>::iter().count(), 2);
<Preimage as QueryPreimage>::drop(&lookup);
assert!(!<Preimage as QueryPreimage>::is_requested(&lookup.hash()));
<Preimage as QueryPreimage>::drop(&legacy);
assert!(!<Preimage as QueryPreimage>::is_requested(&legacy.hash()));
assert_eq!(StatusFor::<Test>::iter().count(), 0);
});
}
#[test]
fn store_preimage_basic_works() {
new_test_ext().execute_with(|| {
let _guard = StorageNoopGuard::default();
let data: Vec<u8> = vec![1; 512]; let encoded = Cow::from(data.encode());
let bound = <Preimage as StorePreimage>::bound(data.clone()).unwrap();
assert_ok!(<Preimage as QueryPreimage>::peek(&bound));
<Preimage as StorePreimage>::unnote(&bound.hash());
assert_err!(<Preimage as QueryPreimage>::peek(&bound), DispatchError::Unavailable);
assert_ok!(<Preimage as StorePreimage>::note(Cow::Borrowed(&data)));
assert_err!(<Preimage as QueryPreimage>::peek(&bound), DispatchError::Unavailable);
assert_ok!(<Preimage as StorePreimage>::note(encoded.clone()));
assert_ok!(<Preimage as StorePreimage>::note(encoded));
assert_ok!(<Preimage as QueryPreimage>::peek(&bound));
<Preimage as StorePreimage>::unnote(&bound.hash());
let data_hash = blake2_256(&data);
<Preimage as StorePreimage>::unnote(&data_hash.into());
});
}
#[test]
fn store_preimage_note_too_large_errors() {
new_test_ext().execute_with(|| {
let len = <Preimage as StorePreimage>::MAX_LENGTH;
let data = vec![0u8; len];
assert_ok!(<Preimage as StorePreimage>::note(data.into()));
let data = vec![0u8; len + 1];
assert_err!(<Preimage as StorePreimage>::note(data.into()), DispatchError::Exhausted);
});
}
#[test]
fn store_preimage_bound_too_large_errors() {
new_test_ext().execute_with(|| {
let len = <Preimage as StorePreimage>::MAX_LENGTH;
let data: Vec<u8> = vec![0; len];
assert_err!(<Preimage as StorePreimage>::bound(data.clone()), DispatchError::Exhausted);
let data: Vec<u8> = vec![0; len - 4];
assert_ok!(<Preimage as StorePreimage>::bound(data.clone()));
});
}