aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md1
-rw-r--r--docs/contracts.rst33
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp6
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp38
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()
}