-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider converting ValidatorManager to an external library #675
Comments
This looks good and I think the abstraction lines are super clear (and clean). I think the open question would be upgrades, but it should be relatively straight forward if you're adding fields to the end, right? I think you could fairly easily upgrade the library before upgrading the calling contract without breaking anything (as long as you aren't removing functionality). |
That's my understanding. It becomes tricky if the caller's state and the library's "state" both need to be upgraded, but in theory it should be possible to do something like this: // Defined in the library
struct Storage {
uint256 varBar;
+ uint256 varBar2;
}
// Defined and accessed in the caller
struct FooStorage {
uint256 varFoo;
Bar.Storage barStorage;
+ uint256 varFoo2;
}
Probably simpler to not upgrade the library at all and instead point to a new instance with the updated logic/storage spec from the caller |
Another interesting consideration is how to upgrade to this external library pattern from a set of stateful contracts. For example, if we move forward with this library approach, and somebody has already deployed the ValidatorManager contracts as they currently are, how can we migrate One approach is to define an I POC'd this here. The v1 contracts consist of |
I was thinking it would look something more like:
|
I like that approach. It maintains state isolation to each individual contract, and offloads the bulk of the contract logic to stateless libraries. The only difference I'd make would be move all the contract logic to the library, and have each method in the class simply fetch the state and pass it to the library. We could apply this pattern up and down the inheritance hierarchy without changing any parent-child relationships. So we'd have something like classDiagram
class ValidatorManager
class PoSValidatorManager
class ValidatorManagerLibrary
class PoSValidatorManagerLibrary
ValidatorManager <|-- PoSValidatorManager
ValidatorManagerLibrary <.. ValidatorManager
PoSValidatorManagerLibrary <.. PoSValidatorManager
Where the dotted lines represent calls into the respective libraries. This would also elide the need for the state migration I described above, since stateful entities persist on upgrades. |
Closing in favor of #662, which is more general. I've linked the comment describing the external library forwarding pattern in that issue. |
Context and scope
The PoSValidatorManager implementation contracts (ERC20TokenStakingManager and NativeTokenStakingManager) are currently flirting with the 24kB contract size limit. This severly limits our ability to continue to develop features. The first strategy the EF lists to work around this is to separate contracts. In the case of ValidatorManager and PoSValidatorManager, this is difficult because each carries its own state.
Discussion and alternatives
The contracts Foo and Bar on this branch demonstrate how to convert a stateful contract to an external library. The general steps to do so are:
Library methods that modify the caller's state can then be invoked from the calling contract.
Another note: currently, there are entry point functions throughout the inheritance hierarchy, including in ValidatorManager. We'll need to move these entry point functions to PoSValidatorManager/PoAValidatorManager.
Open questions
The text was updated successfully, but these errors were encountered: