-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
BREAKING: Add payable modifier #665
Conversation
This severely breaks backwards compatibility and has to be discussed thoroughly. I think it would be better to not have this as a bulit-in compiler feature. If we want to use something like that for analysis and error reporting purposes, the modifier could be added to a standard library. Having said that, I'm not so keen on keeping the hardcoded standard libraries. |
@chriseth Any specific plans for the standard libraries? |
@chriseth I think the reason it should be built in is to support it in the interface JSON. Unless you want to introduce a feature whereby flags can be added to the interface JSON via modifiers or other language features. |
Alternative approach to not break backwards compatibility to have a I do think that the idea of making backwards incompatible changes at this stage, in a coordinated effort, should not be withdrawn. |
Ok, I agree that it might be handy to know whether a function accepts ether especially with auto-generated contract interfaces in mind. I don't especially like the name of the modifier - For the sake of usability, a default of rejecting ether transfer should of course be preferred. It gets more complicated at the point where we have public functions which are helper functions and are called from functions that accept value transfer - then these would throw. |
@chriseth the code currently has Would you rather go for Also this PR doesn't implement the actual code to reject such transactions, so I do not see any backward compatibility break. Rejection should be implemented of course and I would prefer to reject if it value as given to a non- |
I think I would prefer |
@chriseth I would probably go with Regarding the latter I'm not sure how the system will look like once Ether becomes a token contract:
In case 2), |
I don't think we will go with 2. If we do, we can still add a new modifier |
Agreed with @chriseth that we're going for the keyword payable. |
Please check (as in write a test) that this also applies to accessor functions! |
@@ -426,6 +410,13 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) | |||
|
|||
m_context.startFunction(_function); | |||
|
|||
// Reject transaction if value is not accepted, but was received | |||
if (!_function.isPayable()) |
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.
Question is, should it be in visit(FunctionDefiniton)
or appendFunctionSelector
?
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.
visit(FunctionDefinition)
is also used for internal functions, so it should be in the selector or the calldata unpacker.
@chriseth This works now, but a lot tests need to be fixed to include the keyword. |
It may be a good time to review some of those EndToEnd tests whether they actually require a value to be sent at them. Some looked like they may only have it as an oversight. |
@@ -2045,7 +2045,7 @@ BOOST_AUTO_TEST_CASE(contracts_as_addresses) | |||
} | |||
contract test { | |||
helper h; | |||
function test() { h = new helper(); h.send(5); } | |||
function test() payable { h = new helper(); h.send(5); } |
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.
Do you actually handle the constructor?
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.
Yes. I've only added the keyword to the tests where it was failing without the keyword and I've reviewed that the code actually needs it.
I think you added |
We could add another feature: |
Will this mean that getters generated for public variables will throw if they are called with a value transfer? |
@ethernomad yes |
@chriseth I think
|
@axic ok, that makes sense. |
Removed the |
char const* sourceCode = R"( | ||
contract C { | ||
modifier tryCircumvent { | ||
if (false) _ // avoid the function, we should still not accept ether |
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.
Now a semicolon after _
is necessary after #1005.
if (!_function.isConstructor() && !_function.name().empty() && !_function.isPartOfExternalInterface()) | ||
typeError(_function.location(), "Internal functions cannot be payable."); | ||
} | ||
if (_function.isPayable() && _function.isDeclaredConst()) |
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.
This can be merged into the above if
.
Two tests needed:
|
@axic please review again |
@chriseth looks good |
Partially implements #500 and #563. Comments welcome.
Fixes #602.
todo:
contract is payable
should create payable fallback function (and error if there already is one)constant
andpayable
to be mutually exclusive