feat: Allow trees to be linked from the TopHat#79
Conversation
185de13 to
7163a66
Compare
|
quick note: you can check contract size (including compared to max allowed size) with |
|
|
||
| // for grafting one hats tree into another | ||
| // Trees can only be linked to another tree at the tophat level | ||
| mapping(uint32 => uint256) public linkedTreeAdmins; // topHatDomain => hatId |
There was a problem hiding this comment.
Is storage actually made cheaper here by using uint32 here instead of uint256 (ie the full top hat id)? My high level understanding of how storage for mappings works suggests that the answer is no, but I'm not highly confident in that analysis.
There was a problem hiding this comment.
@slgraham It's meant to enforce that only TopHats can be stored here. Nothing else has a uint32 signature.
There was a problem hiding this comment.
We could enforce this at the function interface only (so consumers are forced to ensure they're passing in a topHat id) and make this a uint256.
My main priority here is preventing the need to check that we're only accepting tophats at the code level and letting the interfaces do that for us.
There was a problem hiding this comment.
I see. That makes sense, though I'd think we'd want to trade off the need to do that extra check with the need to cast down to uint32 in a couple other places. Without doing a more in-depth analysis (I'm on mobile currently), my guess is that those casts are cheaper on a unit basis but will occur significantly more often than the check, which will only occur when linking a top hat to another hat.
There was a problem hiding this comment.
The alternative is another check to verify that something is a tophat every time. This is more self-evident in my opinion, and therefore better API design.
There was a problem hiding this comment.
Makes sense, lets go with the uint32 approach.
Food for future thought: I can see us enabling some kind of free-floating hat -- perhaps all hats under the uint32(0) tophat address space -- that can't have any child hats but can be linked and unlinked from trees. Which would likely require a uint256=>uint256 mapping.
A few ideas for naming linked tophats. I think we either tap into the hats memespace or the tree memespace.
@topocount what other naming nuances are you thinking of? |
Tree root is a simple yet self-descriptive choice. If a tree root is linked into another tree, it's still positionally a tree root and more importantly, the root of an address space. The term "Tophat" holds special sudo/admin powers in addition to the characteristics of the tree root so I think good to nominally delineate between the these. This rules out any names containing the name "tophat", and I think "tree root" contains more information than "root hat". figured I'd share this thinking here for the purposes of public documentation |
Just seeing this now 😅 |
69226f6 to
bf87099
Compare
| require(noCircularLinkage(_topHatId, _newAdminHat), 'Circular Linkage'); | ||
| // TODO: hardcode | ||
| uint256 fullTopHatId = uint256(_topHatId) << (256 - TOPHAT_ADDRESS_SPACE); | ||
| uint256 fullTopHatId = uint256(_topHatId) << 224; // (256 - TOPHAT_ADDRESS_SPACE); |
There was a problem hiding this comment.
Does hardcoding change anything here? I was under the impression that constants are "reduced" at compile time, ie that bytecode produced by (256 - TOPHAT_ADDRESS_SPACE) is the same as that produced by 224. Doesn't matter much, obviously; mostly checking my understanding.
There was a problem hiding this comment.
Just did some sensitivity analysis for this calculation with hardcoded vs non-hardcoded:
I was really hoping you were right, but this was a consideration back in pragma 0.4.x as well. Maybe this becomes less of a concern with the optimizer runs increased, but this should be low-hanging fruit for the optimizer at any config since it saves both deployment and tx cost.
There was a problem hiding this comment.
Thanks for running that analysis! I've updated my mental model.
|
This looks good to go from a functionality perspective! Upon further reflection and discussion with @davehrlichman and @nintynick, the ability to link and unlink tophats creates a ton of flexibility for DAOs while still maintaining the gas efficiency and UX advantages of the addressable ID scheme as much as possible. Really strong work! 💪 @topocount, beyond the hardcoding comment just above (re line 49), are there any optimizations you were planning to make within the scope of this PR? |
|
since #78 was merged into |
This feature allows for the following: - effectively infinitely deep trees (really, limited to 255 levels) - migrating suborgs into parent orgs without changing hat Ids A few todos left: - [ ] figure out the naming semantics for linked tophats and other naming nuances. Should we just call them "tree roots" when linked? - [ ] test the new Hats.sol functions - [ ] Add more compreshensive testing to the HatsIdUtils changes - [ ] Add test for circular linkages and safe depth
These bitshifts are cheaper to just hardcode as a single op than throw in an extra utility and add addtional contextual "jump" opcodes
3f9e0ce to
ee5ae76
Compare
|
Reviewed one more time and realized two things:
(We should probably set down some clearer PR acceptance criteria; thanks for bearing with this haphazard review process 😅) |


This feature allows for the following:
A few tasks left: