Search code examples
stringrustsubstraterust-no-std

Runtime Building: String not found in this scope


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

Why are Strings not included in scope? And other std rust types?


Solution

  • 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 Strings incorrectly.

    Furthermore, it is generally bad practice to store Strings 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 Strings 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.