diff options
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | docs/contracts.rst | 33 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 6 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 38 |
4 files changed, 60 insertions, 18 deletions
diff --git a/Changelog.md b/Changelog.md index 5418a205..36aaef1a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ Breaking Changes: * ABI Encoder: Properly pad data from calldata (``msg.data`` and external function parameters). Use ``abi.encodePacked`` for unpadded encoding. * Code Generator: Signed right shift uses proper arithmetic shift, i.e. rounding towards negative infinity. Warning: this may silently change the semantics of existing code! * Code Generator: Revert at runtime if calldata is too short or points out of bounds. This is done inside the ``ABI decoder`` and therefore also applies to ``abi.decode()``. + * Code Generator: Use ``STATICCALL`` for ``pure`` and ``view`` functions. This was already the case in the experimental 0.5.0 mode. * Commandline interface: Remove obsolete ``--formal`` option. * Commandline interface: Rename the ``--julia`` option to ``--yul``. * Commandline interface: Require ``-`` if standard input is used as source. diff --git a/docs/contracts.rst b/docs/contracts.rst index a745bea8..862ec54d 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -451,6 +451,10 @@ View Functions Functions can be declared ``view`` in which case they promise not to modify the state. +.. note:: + If the compiler's EVM target is Byzantium or newer (default) the opcode + ``STATICCALL`` is used. + The following statements are considered modifying the state: #. Writing to state variables. @@ -464,7 +468,7 @@ The following statements are considered modifying the state: :: - pragma solidity ^0.4.16; + pragma solidity >0.4.24; contract C { function f(uint a, uint b) public view returns (uint) { @@ -479,11 +483,12 @@ The following statements are considered modifying the state: Getter methods are marked ``view``. .. note:: - If invalid explicit type conversions are used, state modifications are possible - even though a ``view`` function was called. - You can switch the compiler to use ``STATICCALL`` when calling such functions and thus - prevent modifications to the state on the level of the EVM by adding - ``pragma experimental "v0.5.0";`` + Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode + for ``view`` functions. + This enabled state modifications in ``view`` functions through the use of + invalid explicit type conversions. + By using ``STATICCALL`` for ``view`` functions, modifications to the + state are prevented on the level of the EVM. .. index:: ! pure function, function;pure @@ -494,6 +499,9 @@ Pure Functions Functions can be declared ``pure`` in which case they promise not to read from or modify the state. +.. note:: + If the compiler's EVM target is Byzantium or newer (default) the opcode ``STATICCALL`` is used. + In addition to the list of state modifying statements explained above, the following are considered reading from the state: #. Reading from state variables. @@ -504,7 +512,7 @@ In addition to the list of state modifying statements explained above, the follo :: - pragma solidity ^0.4.16; + pragma solidity >0.4.24; contract C { function f(uint a, uint b) public pure returns (uint) { @@ -513,11 +521,12 @@ In addition to the list of state modifying statements explained above, the follo } .. note:: - If invalid explicit type conversions are used, state modifications are possible - even though a ``pure`` function was called. - You can switch the compiler to use ``STATICCALL`` when calling such functions and thus - prevent modifications to the state on the level of the EVM by adding - ``pragma experimental "v0.5.0";`` + Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode + for ``pure`` functions. + This enabled state modifications in ``pure`` functions through the use of + invalid explicit type conversions. + By using ``STATICCALL`` for ``pure`` functions, modifications to the + state are prevented on the level of the EVM. .. warning:: It is not possible to prevent functions from reading the state at the level diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 483faae4..dfa3e58f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1810,15 +1810,11 @@ void ExpressionCompiler::appendExternalFunctionCall( if (_functionType.bound()) utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack()); - bool const v050 = m_context.experimentalFeatureActive(ExperimentalFeature::V050); auto funKind = _functionType.kind(); bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall; bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; - bool useStaticCall = - _functionType.stateMutability() <= StateMutability::View && - v050 && - m_context.evmVersion().hasStaticCall(); + bool useStaticCall = _functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall(); bool haveReturndatacopy = m_context.evmVersion().supportsReturndata(); unsigned retSize = 0; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 3cd3b9b7..0f314c2a 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -12173,7 +12173,6 @@ BOOST_AUTO_TEST_CASE(abi_encode_call) BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure) { char const* sourceCode = R"( - pragma experimental "v0.5.0"; contract C { uint x; function f() public returns (uint) { @@ -12408,6 +12407,43 @@ BOOST_AUTO_TEST_CASE(senders_balance) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(27))); } +BOOST_AUTO_TEST_CASE(write_storage_external) +{ + char const* sourceCode = R"( + contract C { + uint public x; + function f(uint y) public payable { + x = y; + } + function g(uint y) external { + x = y; + } + function h() public { + this.g(12); + } + } + contract D { + C c = new C(); + function f() public payable returns (uint) { + c.g(3); + return c.x(); + } + function g() public returns (uint) { + c.g(8); + return c.x(); + } + function h() public returns (uint) { + c.h(); + return c.x(); + } + } + )"; + compileAndRun(sourceCode, 0, "D"); + ABI_CHECK(callContractFunction("f()"), encodeArgs(3)); + ABI_CHECK(callContractFunction("g()"), encodeArgs(8)); + ABI_CHECK(callContractFunction("h()"), encodeArgs(12)); +} + BOOST_AUTO_TEST_SUITE_END() } |