A common problem substrate developers might run into: developing a custom pallet to store the mapping into storage with common types, such as String
. As an example:
#[derive(Encode, Decode, Clone, Default, RuntimeDebug)]
pub struct ClusterMetadata {
ip_address: String,
namespace: String,
whitelisted_ips: String,
}
On building the runtime, you get this error for every String
:
|
21 | ip_address: String,
| ^^^^^^ not found in this scope
Strings
not included in scope? And other std
rust types?The error here is not related to no_std
, so you probably just need to import the String
type to get the real errors with using strings in the runtime.
The real issue you will find is that String
is not encodable by Parity SCALE Codec, which is obviously a requirement for any storage item (or most any type you want to use) in the runtime.
So the question is "Why does SCALE not encode String
"?
This is by choice. In general, String
is surprisingly complex type. The Rust book spends a whole section talking about the complexities of the type.
As such, it can easily become a footgun within the runtime environment that people use String
s incorrectly.
Furthermore, it is generally bad practice to store String
s in runtime storage. I think we can easily agree that minimizing storage usage in the runtime is a best practice, and thus you should only put into storage items which you need to be able to derive consensus and state transitions in your runtime. Most often, String
data would be used for metadata, and this kind of usage is not best practice.
If you look more closely at Substrate, you will find that we break this best practice more than once, but this is a decision we explicitly make, having the information at hand to be able to correctly evaluate the cost/benefit.
All of this combined is why String
s are not treated as a first class object in the runtime. Instead, we ask users to encode strings into bytes, and then work with that byte array instead.