Skip to content

Commit a110236

Browse files
Switch pallet-bioauth authorities to WeakBoundedVec and enable generate_storage_info (#208)
* Add required improvements for generating storage ingo at pallet-bioauth * Change MaxNonces value * Use force_from instead of try_push * Return to inital test objects names * Rename test object * Edit a few comments * Improvements based on review * Edit warning message for force_from
1 parent 86246ae commit a110236

File tree

4 files changed

+271
-97
lines changed

4 files changed

+271
-97
lines changed

crates/humanode-runtime/src/lib.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use sp_version::NativeVersion;
3535
use sp_version::RuntimeVersion;
3636

3737
// A few exports that help ease life for downstream crates.
38-
use codec::{Decode, Encode};
38+
use codec::{Decode, Encode, MaxEncodedLen};
3939
pub use frame_support::{
4040
construct_runtime, parameter_types,
4141
traits::{KeyOwnerProofSystem, Randomness},
@@ -207,7 +207,9 @@ impl frame_system::Config for Runtime {
207207
}
208208

209209
/// The wrapper for the robonode public key, that enables ssotring it in the state.
210-
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode, TypeInfo)]
210+
#[derive(
211+
Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode, TypeInfo, MaxEncodedLen,
212+
)]
211213
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
212214
pub struct RobonodePublicKeyWrapper([u8; 32]);
213215

@@ -417,6 +419,8 @@ const TIMESTAMP_HOUR: UnixMilliseconds = 60 * TIMESTAMP_MINUTE;
417419

418420
parameter_types! {
419421
pub const AuthenticationsExpireAfter: UnixMilliseconds = 72 * TIMESTAMP_HOUR;
422+
pub const MaxAuthentications: u32 = 512;
423+
pub const MaxNonces: u32 = 102400;
420424
}
421425

422426
impl pallet_bioauth::Config for Runtime {
@@ -432,6 +436,8 @@ impl pallet_bioauth::Config for Runtime {
432436
type CurrentMoment = CurrentMoment;
433437
type AuthenticationsExpireAfter = AuthenticationsExpireAfter;
434438
type WeightInfo = pallet_bioauth::weights::SubstrateWeight<Runtime>;
439+
type MaxAuthentications = MaxAuthentications;
440+
type MaxNonces = MaxNonces;
435441
}
436442

437443
// Create the runtime by composing the FRAME pallets that were previously
@@ -553,7 +559,7 @@ impl_runtime_apis! {
553559

554560
impl bioauth_consensus_api::BioauthConsensusApi<Block, AuraId> for Runtime {
555561
fn is_authorized(id: &AuraId) -> bool {
556-
Bioauth::active_authentications()
562+
Bioauth::active_authentications().into_inner()
557563
.iter()
558564
.any(|stored_public_key| &stored_public_key.public_key == id)
559565
}

crates/pallet-bioauth/src/lib.rs

+98-18
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
// Fix clippy for sp_api::decl_runtime_apis!
55
#![allow(clippy::too_many_arguments, clippy::unnecessary_mut_passed)]
66

7-
use codec::{Decode, Encode};
8-
use frame_support::traits::IsSubType;
7+
use codec::{Decode, Encode, MaxEncodedLen};
98
use frame_support::weights::DispatchInfo;
9+
use frame_support::{parameter_types, traits::IsSubType, WeakBoundedVec};
1010
pub use pallet::*;
1111
use scale_info::TypeInfo;
1212
#[cfg(feature = "std")]
@@ -85,9 +85,17 @@ pub struct Authenticate<OpaqueAuthTicket, Commitment> {
8585
pub ticket_signature: Commitment,
8686
}
8787

88+
parameter_types! {
89+
/// The maximum length of a single nonce (in bytes).
90+
pub const AuthTicketNonceMaxBytes: u32 = 256;
91+
}
92+
8893
/// The nonce used by robonode in the auth tickets.
8994
pub type AuthTicketNonce = Vec<u8>;
9095

96+
/// The nonce type in this pallet with bounded number of bytes at the nonce.
97+
pub type BoundedAuthTicketNonce = WeakBoundedVec<u8, AuthTicketNonceMaxBytes>;
98+
9199
/// The auth ticket passed to us from the robonode.
92100
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
93101
#[derive(PartialEq, Eq, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo)]
@@ -100,7 +108,7 @@ pub struct AuthTicket<PublicKey> {
100108

101109
/// The state that we keep in the blockchain for an active authentication.
102110
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
103-
#[derive(PartialEq, Eq, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo)]
111+
#[derive(PartialEq, Eq, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo, MaxEncodedLen)]
104112
pub struct Authentication<PublicKey, Moment> {
105113
/// The public key of a validator.
106114
pub public_key: PublicKey,
@@ -119,10 +127,14 @@ pub struct Authentication<PublicKey, Moment> {
119127
pub mod pallet {
120128
use crate::{
121129
weights::WeightInfo, AuthTicket, AuthTicketNonce, Authenticate, Authentication,
122-
CurrentMoment, TryConvert, ValidatorSetUpdater, Verifier,
130+
BoundedAuthTicketNonce, CurrentMoment, TryConvert, ValidatorSetUpdater, Verifier,
123131
};
124132

125-
use frame_support::{pallet_prelude::*, sp_tracing::error, storage::types::ValueQuery};
133+
use codec::MaxEncodedLen;
134+
use frame_support::{
135+
dispatch::DispatchResult, pallet_prelude::*, sp_tracing::error, storage::types::ValueQuery,
136+
WeakBoundedVec,
137+
};
126138
use frame_system::pallet_prelude::*;
127139
use sp_runtime::{app_crypto::MaybeHash, traits::AtLeast32Bit};
128140
use sp_std::prelude::*;
@@ -141,10 +153,15 @@ pub mod pallet {
141153
+ Parameter
142154
+ MaybeSerializeDeserialize
143155
+ Verifier<Self::RobonodeSignature>
144-
+ Default;
156+
+ Default
157+
+ MaxEncodedLen;
145158

146159
/// The public key of the validator.
147-
type ValidatorPublicKey: Member + Parameter + MaybeSerializeDeserialize + MaybeHash;
160+
type ValidatorPublicKey: Member
161+
+ Parameter
162+
+ MaybeSerializeDeserialize
163+
+ MaybeHash
164+
+ MaxEncodedLen;
148165

149166
/// The opaque auth ticket type.
150167
type OpaqueAuthTicket: Parameter + AsRef<[u8]> + Send + Sync;
@@ -156,7 +173,12 @@ pub mod pallet {
156173
>;
157174

158175
/// Type used for expressing timestamp.
159-
type Moment: Parameter + Default + AtLeast32Bit + Copy + MaybeSerializeDeserialize;
176+
type Moment: Parameter
177+
+ Default
178+
+ AtLeast32Bit
179+
+ Copy
180+
+ MaybeSerializeDeserialize
181+
+ MaxEncodedLen;
160182

161183
/// Type used for pretty printing the timestamp.
162184
type DisplayMoment: From<Self::Moment> + core::fmt::Display;
@@ -172,10 +194,17 @@ pub mod pallet {
172194

173195
/// Weight information for extrinsics in this pallet.
174196
type WeightInfo: WeightInfo;
197+
198+
/// The maximum number of authentications.
199+
type MaxAuthentications: Get<u32>;
200+
201+
/// The maximum number of nonces.
202+
type MaxNonces: Get<u32>;
175203
}
176204

177205
#[pallet::pallet]
178206
#[pallet::generate_store(pub(super) trait Store)]
207+
#[pallet::generate_storage_info]
179208
pub struct Pallet<T>(_);
180209

181210
/// The public key of the robonode.
@@ -186,13 +215,17 @@ pub mod pallet {
186215
/// A list of all consumed nonces.
187216
#[pallet::storage]
188217
#[pallet::getter(fn consumed_auth_ticket_nonces)]
189-
pub type ConsumedAuthTicketNonces<T> = StorageValue<_, Vec<AuthTicketNonce>, ValueQuery>;
218+
pub type ConsumedAuthTicketNonces<T: Config> =
219+
StorageValue<_, WeakBoundedVec<BoundedAuthTicketNonce, T::MaxNonces>, ValueQuery>;
190220

191221
/// A list of all active authentications.
192222
#[pallet::storage]
193223
#[pallet::getter(fn active_authentications)]
194-
pub type ActiveAuthentications<T: Config> =
195-
StorageValue<_, Vec<Authentication<T::ValidatorPublicKey, T::Moment>>, ValueQuery>;
224+
pub type ActiveAuthentications<T: Config> = StorageValue<
225+
_,
226+
WeakBoundedVec<Authentication<T::ValidatorPublicKey, T::Moment>, T::MaxAuthentications>,
227+
ValueQuery,
228+
>;
196229

197230
#[pallet::genesis_config]
198231
pub struct GenesisConfig<T: Config> {
@@ -217,9 +250,27 @@ pub mod pallet {
217250
#[pallet::genesis_build]
218251
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
219252
fn build(&self) {
253+
let bounded_consumed_auth_ticket_nonces = WeakBoundedVec::<_, T::MaxNonces>::try_from(
254+
self.consumed_auth_ticket_nonces
255+
.iter()
256+
.cloned()
257+
.map(|nonce| {
258+
BoundedAuthTicketNonce::try_from(nonce)
259+
.expect("Initial nonce len must be less than AuthTicketNonceMaxBytes")
260+
})
261+
.collect::<Vec<_>>(),
262+
)
263+
.expect("Initial nonces must be less than T::MaxNonces");
264+
265+
let bounded_active_authentications =
266+
WeakBoundedVec::<_, T::MaxAuthentications>::try_from(
267+
self.active_authentications.clone(),
268+
)
269+
.expect("Initial authentications must be less than T::MaxAuthentications");
270+
220271
<RobonodePublicKey<T>>::put(&self.robonode_public_key);
221-
<ConsumedAuthTicketNonces<T>>::put(&self.consumed_auth_ticket_nonces);
222-
<ActiveAuthentications<T>>::put(&self.active_authentications);
272+
<ConsumedAuthTicketNonces<T>>::put(bounded_consumed_auth_ticket_nonces);
273+
<ActiveAuthentications<T>>::put(bounded_active_authentications);
223274

224275
<Pallet<T>>::issue_validators_set_init(&self.active_authentications);
225276
}
@@ -285,7 +336,7 @@ pub mod pallet {
285336
/// Validate the incloming authentication attempt, checking the auth ticket data against
286337
/// the passed input.
287338
fn validate_authentication_attempt<'a, T: Config>(
288-
consumed_auth_ticket_nonces: &'a [AuthTicketNonce],
339+
consumed_auth_ticket_nonces: &'a [BoundedAuthTicketNonce],
289340
active_authentications: &'a [Authentication<T::ValidatorPublicKey, T::Moment>],
290341
auth_ticket: &AuthTicket<T::ValidatorPublicKey>,
291342
) -> Result<(), AuthenticationAttemptValidationError<'a, T>> {
@@ -318,7 +369,6 @@ pub mod pallet {
318369
ensure_none(origin)?;
319370

320371
let auth_ticket = Self::extract_auth_ticket_checked(req)?;
321-
322372
let public_key = auth_ticket.public_key.clone();
323373

324374
// Update storage.
@@ -334,12 +384,35 @@ pub mod pallet {
334384

335385
// Update internal state.
336386
let current_moment = T::CurrentMoment::now();
337-
consumed_auth_ticket_nonces.push(auth_ticket.nonce);
338-
active_authentications.push(Authentication {
387+
let mut updated_consumed_auth_ticket_nonces =
388+
consumed_auth_ticket_nonces.clone().into_inner();
389+
390+
updated_consumed_auth_ticket_nonces.push(
391+
BoundedAuthTicketNonce::force_from(
392+
auth_ticket.nonce,
393+
Some("bioauth::authenticate::auth_ticket_nonce"),
394+
),
395+
);
396+
397+
*consumed_auth_ticket_nonces =
398+
WeakBoundedVec::<_, T::MaxNonces>::force_from(
399+
updated_consumed_auth_ticket_nonces,
400+
Some("bioauth::authenticate::nonces"),
401+
);
402+
403+
let mut updated_active_authentications =
404+
active_authentications.clone().into_inner();
405+
updated_active_authentications.push(Authentication {
339406
public_key: public_key.clone(),
340407
expires_at: current_moment + T::AuthenticationsExpireAfter::get(),
341408
});
342409

410+
*active_authentications =
411+
WeakBoundedVec::<_, T::MaxAuthentications>::force_from(
412+
updated_active_authentications,
413+
Some("bioauth::authentication::authentications"),
414+
);
415+
343416
// Issue an update to the external validators set.
344417
Self::issue_validators_set_update(active_authentications.as_slice());
345418

@@ -372,8 +445,15 @@ pub mod pallet {
372445
let update_required =
373446
possibly_expired_authentications_len != active_authentications.len();
374447
if update_required {
448+
// We use force_from and None as a resulted active authentications Vec
449+
// can't become bigger than it was. Just filtering was done before.
450+
let bounded_active_authentications =
451+
WeakBoundedVec::<_, T::MaxAuthentications>::force_from(
452+
active_authentications.clone(),
453+
None,
454+
);
375455
Self::issue_validators_set_update(active_authentications.as_slice());
376-
<ActiveAuthentications<T>>::put(active_authentications);
456+
<ActiveAuthentications<T>>::put(bounded_active_authentications);
377457
}
378458

379459
T::WeightInfo::on_initialize(update_required)

crates/pallet-bioauth/src/mock.rs

+31-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::cell::RefCell;
22

33
use crate::{self as pallet_bioauth, weights, AuthTicket, TryConvert};
4-
use codec::{Decode, Encode};
4+
use codec::{Decode, Encode, MaxEncodedLen};
55
use frame_support::parameter_types;
66
use frame_system as system;
77
use mockall::{mock, predicate};
@@ -36,9 +36,12 @@ frame_support::construct_runtime!(
3636
}
3737
);
3838

39+
/// Validator public key. Should be bounded.
40+
pub type ValidatorPublicKey = [u8; 32];
41+
3942
#[derive(PartialEq, Eq, Default, Clone, Encode, Decode, Hash, Debug, TypeInfo)]
4043
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
41-
pub struct MockOpaqueAuthTicket(pub AuthTicket<Vec<u8>>);
44+
pub struct MockOpaqueAuthTicket(pub AuthTicket<ValidatorPublicKey>);
4245

4346
impl AsRef<[u8]> for MockOpaqueAuthTicket {
4447
fn as_ref(&self) -> &[u8] {
@@ -48,10 +51,12 @@ impl AsRef<[u8]> for MockOpaqueAuthTicket {
4851

4952
pub struct MockAuthTicketConverter;
5053

51-
impl TryConvert<MockOpaqueAuthTicket, AuthTicket<Vec<u8>>> for MockAuthTicketConverter {
54+
impl TryConvert<MockOpaqueAuthTicket, AuthTicket<ValidatorPublicKey>> for MockAuthTicketConverter {
5255
type Error = Infallible;
5356

54-
fn try_convert(value: MockOpaqueAuthTicket) -> Result<AuthTicket<Vec<u8>>, Self::Error> {
57+
fn try_convert(
58+
value: MockOpaqueAuthTicket,
59+
) -> Result<AuthTicket<ValidatorPublicKey>, Self::Error> {
5560
Ok(value.0)
5661
}
5762
}
@@ -71,31 +76,39 @@ impl super::Verifier<Vec<u8>> for MockVerifier {
7176
}
7277
}
7378

79+
impl MaxEncodedLen for MockVerifier {
80+
fn max_encoded_len() -> usize {
81+
panic!("should be unused in tests")
82+
}
83+
}
84+
7485
mock! {
7586
pub ValidatorSetUpdater {
76-
pub fn update_validators_set(&self, validator_public_keys: Vec<Vec<u8>>);
77-
pub fn init_validators_set(&self, validator_public_keys: Vec<Vec<u8>>);
87+
pub fn update_validators_set(&self, validator_public_keys: Vec<ValidatorPublicKey>);
88+
pub fn init_validators_set(&self, validator_public_keys: Vec<ValidatorPublicKey>);
7889
}
7990
}
8091

8192
thread_local! {
8293
pub static MOCK_VALIDATOR_SET_UPDATER: RefCell<MockValidatorSetUpdater> = RefCell::new(MockValidatorSetUpdater::new());
8394
}
8495

85-
impl super::ValidatorSetUpdater<Vec<u8>> for MockValidatorSetUpdater {
86-
fn update_validators_set<'a, I: Iterator<Item = &'a Vec<u8>> + 'a>(validator_public_keys: I)
87-
where
88-
Vec<u8>: 'a,
96+
impl super::ValidatorSetUpdater<ValidatorPublicKey> for MockValidatorSetUpdater {
97+
fn update_validators_set<'a, I: Iterator<Item = &'a ValidatorPublicKey> + 'a>(
98+
validator_public_keys: I,
99+
) where
100+
ValidatorPublicKey: 'a,
89101
{
90102
MOCK_VALIDATOR_SET_UPDATER.with(|val| {
91103
val.borrow_mut()
92104
.update_validators_set(validator_public_keys.cloned().collect())
93105
});
94106
}
95107

96-
fn init_validators_set<'a, I: Iterator<Item = &'a Vec<u8>> + 'a>(validator_public_keys: I)
97-
where
98-
Vec<u8>: 'a,
108+
fn init_validators_set<'a, I: Iterator<Item = &'a ValidatorPublicKey> + 'a>(
109+
validator_public_keys: I,
110+
) where
111+
ValidatorPublicKey: 'a,
99112
{
100113
MOCK_VALIDATOR_SET_UPDATER.with(|val| {
101114
val.borrow_mut()
@@ -175,6 +188,8 @@ pub const AUTHENTICATIONS_EXPIRE_AFTER: UnixMilliseconds = TIMESTAMP_MINUTE;
175188

176189
parameter_types! {
177190
pub const AuthenticationsExpireAfter: UnixMilliseconds = AUTHENTICATIONS_EXPIRE_AFTER;
191+
pub const MaxAuthentications: u32 = 512;
192+
pub const MaxNonces: u32 = 512;
178193
}
179194

180195
pub struct DisplayMoment;
@@ -195,7 +210,7 @@ impl pallet_bioauth::Config for Test {
195210
type Event = Event;
196211
type RobonodePublicKey = MockVerifier;
197212
type RobonodeSignature = Vec<u8>;
198-
type ValidatorPublicKey = Vec<u8>;
213+
type ValidatorPublicKey = ValidatorPublicKey;
199214
type OpaqueAuthTicket = MockOpaqueAuthTicket;
200215
type AuthTicketCoverter = MockAuthTicketConverter;
201216
type ValidatorSetUpdater = MockValidatorSetUpdater;
@@ -204,6 +219,8 @@ impl pallet_bioauth::Config for Test {
204219
type CurrentMoment = MockCurrentMomentProvider;
205220
type AuthenticationsExpireAfter = AuthenticationsExpireAfter;
206221
type WeightInfo = weights::SubstrateWeight<Test>;
222+
type MaxAuthentications = MaxAuthentications;
223+
type MaxNonces = MaxNonces;
207224
}
208225

209226
/// Build test externalities from the default genesis.

0 commit comments

Comments
 (0)