Summary of the design:
- Tries are stored as immutable, copy-on-write trees
- All trie data is stored in the `TrieData` segment. Since it's immutable, data is never modified/deleted, new versions are just appended at the end.
- In order to support reverts, each context stores a pointer to the initial state trie version, plus the initial version of each storage trie.
One variation which may be worth considering is storing the whole state trie as one big trie (with sub-tries for storage). Reverts would then be simpler - we'd replace a single pointer. I thought that approach might make hashing the trie a bit more complex, as the node associated with an account would be a special type of node, rather than just another leaf. Either approach seems reasonable though.
- `GlobalMetadata` - offsets for global kernel variables in memory
- `ContextMetadata` - offsets for context-specific kernel variables in memory
- `GAS_CONSTANTS`, based on the yellowpaper
Also move constants to a separate module since `aggregator` was getting long.
It's a bit more type-safe (can't mix up segment with context or virtual addr), and this way uniqueness of ordinals is enforced, partially addressing a concern raised in #591.
To avoid making `Segment` public (which I don't think would be appropriate), I had to make some other visibility changes, and had to move `generate_random_memory_ops` into the test module.