Skip to content
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

Improve encapsulation in the Heritable contract #692

Closed
eternauta1337 opened this issue Jan 18, 2018 · 7 comments
Closed

Improve encapsulation in the Heritable contract #692

eternauta1337 opened this issue Jan 18, 2018 · 7 comments
Labels
good first issue Low hanging fruit for new contributors to get involved!

Comments

@eternauta1337
Copy link
Contributor

heir is public and has a setter setHeir

Since we are providing a setter, we should also provide a getter and make heir private. It ensures that inheriting contracts cannot modify the heir in an unintended way.

This is a general practice we are starting to adopt in all OpenZeppelin, i.e. more extensive use of private contract variables.

We may want to consider this for heartbeatTimeout and timeOfDeath as well.

@azavalla something that might interest you?

@eternauta1337 eternauta1337 added good first issue Low hanging fruit for new contributors to get involved! enhancement labels Jan 18, 2018
@trejas
Copy link
Contributor

trejas commented Jan 20, 2018

Should the getters be accessible only to the owner of the contract, or should they be publicly accessible?

@shrugs
Copy link
Contributor

shrugs commented Jan 20, 2018

The getter should be public, imo.

@azavalla
Copy link
Contributor

Reducing the public API of the contracts minimizes the number of guarantees we have to make to the code using our contract (thus reducing the places where we have to watch out for compatibility issues), giving us more freedom to change -private- implementation details.

Also, being a framework focused on security, it makes sense to try and avoid having developers extending a contract in an unintended way. But to be honest, I'm not sure making members private provides you that much safety in the face of a inheriting contracts making an unintended use. Explicitly overriding a method/variable is a conscious decision. I guess it makes sense if you add logic to the setter to check an invariant.

The cost you pay is extendability. We are restricting the library only to the intended use cases, i.e. the ones we can imagine right now.

IMHO, given OZ is an open source library, if there's doubts about the appropiate visibility, we should choose the less strict approach if we want to promote people using and extending OZ. This way we wont promote people copy-pasting a contract just because they had a slightly different use case we couldn't think of.

contract Heritable, likewise most of OZ contracts, is designed to be inheritable. I think the approach in the general case should be:
"Are you sure that a subclass will never want to override this method ? Make it private, else make it internal or public (and document it accordingly)."

@ajsantander what do you think?

frangio pushed a commit that referenced this issue Jan 26, 2018
* Modified Gitignore for Sublime

* Added getter functions for public variables

* Added encapsulation to Heritable public variables.

* Added encapsulation to Heritable public variables.

* Added encapsulation to Heritable public variables.

* Updated tests to use getter methods instead of, now, private variables.

* Conformed variable names to current conventions.

* Requested changes

* revert package-lock.json changes
@frangio
Copy link
Contributor

frangio commented Jan 26, 2018

Fixed in #702.

@frangio frangio closed this as completed Jan 26, 2018
@azavalla
Copy link
Contributor

azavalla commented Feb 3, 2018

@frangio any thoughts on this ?

@frangio
Copy link
Contributor

frangio commented Feb 6, 2018

We agree that there's a trade-off between extensibility and security.

I guess it makes sense if you add logic to the setter to check an invariant.

Yeah, in fact, this is aligned with the reasoning behind this issue. In this case it was not checking an invariant that we wanted to enforce, but emitting the event HeirChanged and the heartbeat whenever the state variable is changed. It's true that if a state variable didn't have any sort of additional logic necessary when modified, or invariants to be maintained, it doesn't need to be private.

Explicitly overriding a method/variable is a conscious decision.

I disagree with this as an argument, because we aim to provide APIs which are hard to use insecurely. This includes external APIs, as well as internal APIs for contracts that extend via inheritance. If one of our contracts has a public or internal state variable heir, the setter for that variable heir = ... is part of our internal API, i.e. we are telling the developer "feel free to set this variable to any value you want, do not expect any odd consequences". Not emitting the HeirChanged event is such an odd consequence, so it made sense to me to make it private.

There is still something a little bit weird: a contract could override the setHeir function. The language provides no way to prevent that, but we would probably use it if it did (ethereum/solidity#463). Here's where we see ourselves forced to draw a line and say: overriding this method would be a conscious decision and the developer should know that they may be causing trouble. But I feel that overriding a function is an even more conscious decision than setting a variable, which is why I'm more comfortable with it.

@frangio
Copy link
Contributor

frangio commented Feb 6, 2018

IMHO, given OZ is an open source library, if there's doubts about the appropiate visibility, we should choose the less strict approach if we want to promote people using and extending OZ. This way we wont promote people copy-pasting a contract just because they had a slightly different use case we couldn't think of.

I definitely see where you're going with this and I share a similar concern. I think that we want to promote people extending OZ in secure ways, and we have to set the library up for being securely extended. private state variables enable more secure extension. Even if they may preclude some types of extension, we have to design our APIs so that the extensions precluded are insecure ones. In the case of Heritable, setting the heir without emitting the HeirChanged event would be considered insecure.

I hope the reasoning was made clearer now. Let me know if you have any other thoughts about it. :-)

ProphetDaniel pushed a commit to classicdelta/Smart-Contracts that referenced this issue Mar 9, 2018
* Modified Gitignore for Sublime

* Added getter functions for public variables

* Added encapsulation to Heritable public variables.

* Added encapsulation to Heritable public variables.

* Added encapsulation to Heritable public variables.

* Updated tests to use getter methods instead of, now, private variables.

* Conformed variable names to current conventions.

* Requested changes

* revert package-lock.json changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Low hanging fruit for new contributors to get involved!
Projects
None yet
Development

No branches or pull requests

5 participants