-
Notifications
You must be signed in to change notification settings - Fork 82
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
Add Stylus constructors #184
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR is looking great. The implementation is concise and well-thought out. Just had a few minor comments before approval
Looks good to me, pending testing integration with the other components. One interesting thing about doing the constructor guard check is that it is possible to call the user- defined constructor function from other contract functions. I could see this being useful to perhaps re-initialize a contract under some certain conditions, but also it may be a source of confusion if someone reviewing the code incorrectly assumes the constructor may only be called once. One option is to inject the constructor guard call into the body of the constructor function. If we want to allow explicit re-calling of the constructor from other constructor methods, this would have to be conditional based on disabling some feature flag. Interested in hearing others' opinions on this. |
I prefer the current WYSIWYG approach, which doesn't change the code. |
Co-authored-by: Raul Jordan <[email protected]>
Co-authored-by: Raul Jordan <[email protected]>
This feature provides a standard way to deploy, activate, and initialize a stylus contract atomically. Without constructors, it isn’t possible to guarantee that the Stylus contract initialization code will be executed before other methods.
Constructor Definition
In a Stylus contract, the constructor should be defined as the following.
There must be either no constructor definition or a single constructor for a contract. Like Solidity, function overloading for constructors is not supported.
The constructor function must be annotated with the
#[constructor]
attribute. It can have any name, and it will always have the signatureconstructor()
regardless of the name and number of parameters. We hardcode the signature of the method to ensure the correct method is called when deploying the contract. If there is a method calledconstructor
in the contract but it is not annotated with the expected macro, the SDK should emit an error stating that it expects the constructor macro.The constructor must receive the self parameter, and it can have any number of other parameters. The values for these parameters will be passed to constructor when deploying the contract. The constructor should return no value or a result value with an unit type and a vector of bytes (
Result<(), Vec<u8>>
). If the constructor returns an error, the deployment will revert.The SDK will ensure the constructor is called only once. To do so, it will wrap the constructor with a function that reads and writes to a specific slot in storage. When called, the constructor wrapper will check the contents of the specific slot and it will revert if it is different from zero. Then, after executing the constructor method, the wrapper will write a value to the specific slot, ensuring the next call to the constructor will revert. The specific slot address will be hardcoded to
keccak256(”stylus_constructor”)
.