mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #4428 from ethereum/enforce_staticcall_view
[BREAKING] Enforce STATICCALL for view and pure
This commit is contained in:
commit
fa8102880f
@ -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.
|
* 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: 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: 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: Remove obsolete ``--formal`` option.
|
||||||
* Commandline interface: Rename the ``--julia`` option to ``--yul``.
|
* Commandline interface: Rename the ``--julia`` option to ``--yul``.
|
||||||
* Commandline interface: Require ``-`` if standard input is used as source.
|
* Commandline interface: Require ``-`` if standard input is used as source.
|
||||||
|
@ -451,6 +451,10 @@ View Functions
|
|||||||
|
|
||||||
Functions can be declared ``view`` in which case they promise not to modify the state.
|
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:
|
The following statements are considered modifying the state:
|
||||||
|
|
||||||
#. Writing to state variables.
|
#. 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 {
|
contract C {
|
||||||
function f(uint a, uint b) public view returns (uint) {
|
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``.
|
Getter methods are marked ``view``.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
If invalid explicit type conversions are used, state modifications are possible
|
Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode
|
||||||
even though a ``view`` function was called.
|
for ``view`` functions.
|
||||||
You can switch the compiler to use ``STATICCALL`` when calling such functions and thus
|
This enabled state modifications in ``view`` functions through the use of
|
||||||
prevent modifications to the state on the level of the EVM by adding
|
invalid explicit type conversions.
|
||||||
``pragma experimental "v0.5.0";``
|
By using ``STATICCALL`` for ``view`` functions, modifications to the
|
||||||
|
state are prevented on the level of the EVM.
|
||||||
|
|
||||||
.. index:: ! pure function, function;pure
|
.. 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.
|
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:
|
In addition to the list of state modifying statements explained above, the following are considered reading from the state:
|
||||||
|
|
||||||
#. Reading from state variables.
|
#. 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 {
|
contract C {
|
||||||
function f(uint a, uint b) public pure returns (uint) {
|
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::
|
.. note::
|
||||||
If invalid explicit type conversions are used, state modifications are possible
|
Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode
|
||||||
even though a ``pure`` function was called.
|
for ``pure`` functions.
|
||||||
You can switch the compiler to use ``STATICCALL`` when calling such functions and thus
|
This enabled state modifications in ``pure`` functions through the use of
|
||||||
prevent modifications to the state on the level of the EVM by adding
|
invalid explicit type conversions.
|
||||||
``pragma experimental "v0.5.0";``
|
By using ``STATICCALL`` for ``pure`` functions, modifications to the
|
||||||
|
state are prevented on the level of the EVM.
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
It is not possible to prevent functions from reading the state at the level
|
It is not possible to prevent functions from reading the state at the level
|
||||||
|
@ -1810,15 +1810,11 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
if (_functionType.bound())
|
if (_functionType.bound())
|
||||||
utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack());
|
utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack());
|
||||||
|
|
||||||
bool const v050 = m_context.experimentalFeatureActive(ExperimentalFeature::V050);
|
|
||||||
auto funKind = _functionType.kind();
|
auto funKind = _functionType.kind();
|
||||||
bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall;
|
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 isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode;
|
||||||
bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall;
|
bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall;
|
||||||
bool useStaticCall =
|
bool useStaticCall = _functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall();
|
||||||
_functionType.stateMutability() <= StateMutability::View &&
|
|
||||||
v050 &&
|
|
||||||
m_context.evmVersion().hasStaticCall();
|
|
||||||
|
|
||||||
bool haveReturndatacopy = m_context.evmVersion().supportsReturndata();
|
bool haveReturndatacopy = m_context.evmVersion().supportsReturndata();
|
||||||
unsigned retSize = 0;
|
unsigned retSize = 0;
|
||||||
|
@ -12487,7 +12487,6 @@ BOOST_AUTO_TEST_CASE(abi_encode_call)
|
|||||||
BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure)
|
BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
pragma experimental "v0.5.0";
|
|
||||||
contract C {
|
contract C {
|
||||||
uint x;
|
uint x;
|
||||||
function f() public returns (uint) {
|
function f() public returns (uint) {
|
||||||
@ -12722,6 +12721,43 @@ BOOST_AUTO_TEST_CASE(senders_balance)
|
|||||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(27)));
|
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()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user