3

Consider the following scenario, where I have a BoundedVec which has bound parameter MaxItems. Now this MaxItems parameter would be configured in the runtime.

pub type StorageItem<T: Config<I>, I: 'static = ()> =
        StorageValue<_, BoundedVec<Id, T::MaxItems>, ValueQuery>;

Let's say that MaxItems was set to 10. And during the course of the operation of the chain the BoundedVec StorageItem is (fully) populated with 10 items.

If in a runtime upgrade I reduce this MaxItems value in the runtime to 5 (5 < 10). Will my StorageItem refuse to decode perhaps with a panic? Or will it just decode the first 5 that it finds...

What would be the behavior here? And how about similar bounded structs such as BoundedBtreeMap and BoundedBtreeSet?

1 Answer 1

3

Good question!

Just reducing the bound will indeed result in a decoding error. It will behave like any other decode error; not panic but either return None or Default depending on whether you are using OptionQuery or ValueQuery.
If you want to properly reduce the bound, you have to truncate the vector in a migration to ensure that it will fit into the new bound. BoundedBtreeMap and BoundedBtreeSet behave likewise.
There also is WeakBoundedVec, but that is of limited usefulness for cases where you are unsure about the bound, since it will decode anyway.

The reason to have BoundedVec in the first place is to know how much data we have to read from storage in the worst case.
The worst-case of BoundedVec<T, L> would be about T::max_encoded_len() * L::get() (excluding its prefixed length). This is important to calculate pre-dispatch PoV weights (chromatic weights, aka Weights V2). Now currently the logic for reading a BoundedVec does actually not enforce it, since it first decodes and then throws the vector away if it is too long. It would be better to only read the length first and check.
Anyway, in short; It can be used to restrict some theoretical worst cases since Vec could have up to usize::MAX elements.
So for now it probably does not make much difference if you use Weak or not, since Weak and Bounded both don't really enforce the worst case, but in the future Bounded hopefully will.
IMHO it is just better practice to use Bounded, but I see that it very dangerous in some cases and requires much attention not to brick a chain.

3
  • Thanks for the answer! I have two more questions: 1. "... but that is of limited usefulness for cases where you are unsure about the bound, since it will decode anyway." But this sounds very useful for when we do not know what the bound will be in the future, right? Because then persistent data can still be accessed. 2. Is there a problem with using WeakBoundedVec everywhere instead of BoundedVec? Sounds like a nice hack to prevent storage dependent logic from breaking if we forget to perform a storage migration when we decrease the bound. Jan 17, 2023 at 15:33
  • I updated the answer. Jan 18, 2023 at 0:38
  • Thank you! @Oliver Tale-Yazdi Feb 1, 2023 at 15:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.