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. | ||||
|  * 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. | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -12487,7 +12487,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) { | ||||
| @ -12722,6 +12721,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() | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user