Skip to content

Move msg.gas to global function gasleft(). Closes #2971.#3643

Merged
chriseth merged 6 commits intodevelopfrom
gasleft
Mar 5, 2018
Merged

Move msg.gas to global function gasleft(). Closes #2971.#3643
chriseth merged 6 commits intodevelopfrom
gasleft

Conversation

@ekpyron
Copy link
Collaborator

@ekpyron ekpyron commented Mar 5, 2018

  • Am I right in assuming that due to scoping introducing the gasleft as a new global in fact does not break existing code?

  • I wasn't sure what kind of tests to add, so I added several tests - not all of them may be necessary. Also: the tests share the same name - is that ok, since they test the same feature or should they still have distinct names?

}
)";
compileAndRun(sourceCode);
BOOST_REQUIRE(callContractFunction("getGasLeft()") == encodeArgs(99978604));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is probably way too unstable.

)";
CHECK_ERROR(text, TypeError, "Member \"gas\" not found or not visible after argument-dependent lookup in msg");
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test where gasleft is a local variable or function and check that resolution works correctly.

It could also test what happens if the signature of the function is different and whether overload resolution is performed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding overload resolution: what's the expected behaviour here?

I just checked the behaviour of the global function "now" and noticed, that if "now" is overwritten/shadowed by a local function, then the global "now" will be inaccessible, even if the local function has a different signature... so at the moment overload resolution does not seem to work in such cases.

As of now "gasleft" has the same behaviour. I'm about to add tests for shadowing gasleft with local functions/variables, but I'm not sure about overload resolution - should overload resolution find the global function, if a local function has a different signature? If so, this should probably also be adjusted for the case of "now"...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it should be consistent with the other cases: Shadowing between scopes, overloading in the same scope.

that accesses storage, blockchain data (e.g. ``now``, ``this.balance`` or
``block.number``) or
execution data (``msg.gas``) or make calls to external contracts are disallowed. Expressions
execution data (``msg.value``) or make calls to external contracts are disallowed. Expressions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would still keep the gas example, since this is a little special. I actually only wondered today whether we allow gasleft in pure functions or not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, perhaps it is best to provide both value and gas.

}

MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const *_contract) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* is left-aligned

};
if (!v050)
members.emplace_back("gas", make_shared<IntegerType>(256));
return MemberList::MemberMap(members);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type of members should be identical to memberList::MemberMap shouldn't it?


bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
{
const bool v050 = m_context.experimentalFeatureActive(ExperimentalFeature::V050);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be bool const

else if (member == "origin")
m_context << Instruction::ORIGIN;
else if (member == "gas")
else if (!v050 && member == "gas")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use solAssert(!v050, "") here instead of just checking.

@ekpyron ekpyron requested a review from erak March 5, 2018 16:10
@chriseth
Copy link
Contributor

chriseth commented Mar 5, 2018

Re-triggered test, seems to be infrastructure issue.

function f() public returns (uint256 val) { return msg.gas; }
}
)";
CHECK_SUCCESS(text);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please always use CHECK_SUCCESS_NO_WARNINGS

char const* text = R"(
contract C {
function gasleft() public pure returns (bytes32 val) { return "abc"; }
function f() public pure { bytes32 val = gasleft(); assert (val == "abc"); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is not executed, so the assert is not an actual test.

Copy link
Collaborator Author

@ekpyron ekpyron Mar 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "assert (val == "abc");" will not trigger an error (I only added it to supress an "unused variable" warning) - but if the compiler were to resolve to global "gasleft", which returns an uint256, the assignement "bytes32 val = gasleft();" should trigger an invalid conversion error, so it's still a valid test for the resolution... I will move that part to an EndToEnd test nonetheless.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see - ok!

@chriseth chriseth merged commit 3793aa4 into develop Mar 5, 2018
@axic
Copy link
Contributor

axic commented Mar 5, 2018

@ekpyron @chriseth we have never discussed this issue, whether it should be a function or a "volatile" variable.

@axic
Copy link
Contributor

axic commented Mar 5, 2018

Also should raise a warning if using msg.gas.

@chriseth
Copy link
Contributor

chriseth commented Mar 5, 2018

@axic created an issue for the warning, but the description of your issue was rather clear that it should be a function. We discussed this and concluded that indeed, it should be a function. Note that both address.balance and now are at least static between external calls.

@axic
Copy link
Contributor

axic commented Mar 5, 2018

The issue had both options, but I don't remember any discussion.

I had no preference, I like the function better as having volatile variables isn't a good idea at the moment.

"block.difficulty",
"block.number",
"block.gaslimit",
"gasleft()",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ekpyron @chriseth I guess this should have been gasleft without parentheses, but the code still compiles (var x = gasleft; x; vs var x = gasleft(); x;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

block.blockhash(7) above also uses parentheses. We should have tests for both versions if such a magic global is a function.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh cool, I think it must be correct this way, the others are variables, while these two are functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants