A dynamic Eternal Storage design that won't require an upgrade

Context

Hello :hand_with_fingers_splayed:

I'm trying to decide what would be the best path for implementing an upgradable Dapp. My constraints are;

  • I'm developing for a permissioned network where gas is no issue
  • I will be dealing with HUGE amounts of records in my smart contract's storage
  • I will be using complex structs that can change over time
  • I want to be able to release quick bug fixes

Resources I read Before Posting

Question

I'm aware of Proxies and unstructured storage patterns. However, keeping the storage layout in the back of my head all the time when I'm developing my dapp seems something that I don't want to do. And it really looks weird to have storage contracts like in order to avoid collisions between implementation contracts;

contract V1Storage {}
contract V2Storage extends V1Storage {}
contract V3Storage extends V2Storage {}
....

So what seems like a good idea is that (given I'm building for a permissioned network) to have a separate storage contract that is similar to the one in https://blog.colony.io/writing-upgradeable-contracts-in-solidity-6743f0eecc88/ but with additional fields like below to handle my structs:

mapping(bytes32 => mapping(bytes32 => bytes))

This way the structs are stored as byte arrays and the implementation contract could use its own logic to decode the byte array given the version of the respective struct. Thoughts?

Hi Anil :waving_hand:,

You're tackling a very relevant challenge — especially in permissioned networks where performance isn't as constrained, but long-term maintainability and flexibility are key.

Your approach of using a layered mapping(bytes32 => mapping(bytes32 => bytes)) as a version-aware storage backend is solid. It effectively decouples storage layout from implementation logic, making upgrades safer and less error-prone. This is especially useful when dealing with large structs that may evolve over time.

Given your context (permissioned network, high record volume, evolving data types), this abstraction seems like a strong fit.

You might also want to explore combining this with a registry pattern or version-controlled storage namespaces to better organize your data.

Would love to hear how you plan to structure the decoding logic for each version!