aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2017-08-24 21:53:13 +0800
committerGitHub <noreply@github.com>2017-08-24 21:53:13 +0800
commitd3fd6a8800ddd15be509971b516bb823bbd93b86 (patch)
tree49ef0252dd6902d46aed69b581494984e4697c41
parent65d78f36c1f5b88546261bc005ef952065d34adf (diff)
parentf646247dfb7d398255b3e2cc1aa6e25fe8424af3 (diff)
downloaddexon-solidity-d3fd6a8800ddd15be509971b516bb823bbd93b86.tar
dexon-solidity-d3fd6a8800ddd15be509971b516bb823bbd93b86.tar.gz
dexon-solidity-d3fd6a8800ddd15be509971b516bb823bbd93b86.tar.bz2
dexon-solidity-d3fd6a8800ddd15be509971b516bb823bbd93b86.tar.lz
dexon-solidity-d3fd6a8800ddd15be509971b516bb823bbd93b86.tar.xz
dexon-solidity-d3fd6a8800ddd15be509971b516bb823bbd93b86.tar.zst
dexon-solidity-d3fd6a8800ddd15be509971b516bb823bbd93b86.zip
Merge pull request #2745 from ethereum/statemutability-pure
Introduce pure specifier on functions
-rw-r--r--Changelog.md3
-rw-r--r--docs/abi-spec.rst2
-rw-r--r--docs/contracts.rst23
-rw-r--r--docs/grammar.txt2
-rw-r--r--docs/miscellaneous.rst5
-rw-r--r--docs/types.rst2
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp2
-rw-r--r--libsolidity/ast/ASTEnums.h4
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp4
-rw-r--r--libsolidity/interface/ABI.cpp2
-rw-r--r--libsolidity/parsing/Parser.cpp2
-rw-r--r--libsolidity/parsing/Token.h4
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp55
-rw-r--r--test/libsolidity/SolidityParser.cpp10
14 files changed, 107 insertions, 13 deletions
diff --git a/Changelog.md b/Changelog.md
index 1ea3f6c8..8c540a28 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,7 +1,8 @@
### 0.4.16 (unreleased)
Features:
- * ABI JSON: Include new field ``statemutability`` with values ``view``, ``nonpayable`` and ``payable``.
+ * Introduce ``pure`` functions. The pureness is not enforced yet, use with care.
+ * ABI JSON: Include new field ``statemutability`` with values ``pure``, ``view``, ``nonpayable`` and ``payable``.
* Analyzer: Experimental partial support for Z3 SMT checker.
* Parser: Display previous visibility specifier in error if multiple are found.
* Parser: Introduce ``view`` keyword on functions (``constant`` remains an alias for ``view``).
diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst
index 159bd6c7..036b1ac8 100644
--- a/docs/abi-spec.rst
+++ b/docs/abi-spec.rst
@@ -295,7 +295,7 @@ The JSON format for a contract's interface is given by an array of function and/
- `outputs`: an array of objects similar to `inputs`, can be omitted if function doesn't return anything;
- `constant`: `true` if function is :ref:`specified to not modify blockchain state <view-functions>`);
- `payable`: `true` if function accepts ether, defaults to `false`;
-- `statemutability`: a string with one of the following values: `view` (same as `constant` above), `nonpayable` and `payable` (same as `payable` above).
+- `statemutability`: a string with one of the following values: `pure` (:ref:`specified to not read blockchain state <pure-functions>`), `view` (same as `constant` above), `nonpayable` and `payable` (same as `payable` above).
`type` can be omitted, defaulting to `"function"`.
diff --git a/docs/contracts.rst b/docs/contracts.rst
index 0f1a882c..50e7f3d1 100644
--- a/docs/contracts.rst
+++ b/docs/contracts.rst
@@ -475,7 +475,7 @@ Functions can be declared ``view`` in which case they promise not to modify the
contract C {
function f(uint a, uint b) view returns (uint) {
- return a * (b + 42);
+ return a * (b + 42) + now;
}
}
@@ -488,6 +488,27 @@ Functions can be declared ``view`` in which case they promise not to modify the
.. warning::
The compiler does not enforce yet that a ``view`` method is not modifying state.
+.. _pure-functions:
+
+**************
+Pure Functions
+**************
+
+Functions can be declared ``pure`` in which case they promise not to read from or modify the state.
+
+::
+
+ pragma solidity ^0.4.0;
+
+ contract C {
+ function f(uint a, uint b) pure returns (uint) {
+ return a * (b + 42);
+ }
+ }
+
+.. warning::
+ The compiler does not enforce yet that a ``pure`` method is not reading from the state.
+
.. index:: ! fallback function, function;fallback
.. _fallback-function:
diff --git a/docs/grammar.txt b/docs/grammar.txt
index 36ba36f0..041728c5 100644
--- a/docs/grammar.txt
+++ b/docs/grammar.txt
@@ -53,7 +53,7 @@ ArrayTypeName = TypeName '[' Expression? ']'
FunctionTypeName = 'function' TypeNameList ( 'internal' | 'external' | StateMutability )*
( 'returns' TypeNameList )?
StorageLocation = 'memory' | 'storage'
-StateMutability = 'constant' | 'view' | 'payable'
+StateMutability = 'pure' | 'constant' | 'view' | 'payable'
Block = '{' Statement* '}'
Statement = IfStatement | WhileStatement | ForStatement | Block | InlineAssemblyStatement |
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index 7889fff2..e78c4807 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -500,12 +500,13 @@ Function Visibility Specifiers
- ``internal``: only visible internally
-.. index:: modifiers, constant, anonymous, indexed
+.. index:: modifiers, pure, view, payable, constant, anonymous, indexed
Modifiers
=========
-- ``view`` for functions: Disallow modification of state - this is not enforced yet.
+- ``pure`` for functions: Disallows modification or access of state - this is not enforced yet.
+- ``view`` for functions: Disallows modification of state - this is not enforced yet.
- ``payable`` for functions: Allows them to receive Ether together with a call.
- ``constant`` for state variables: Disallows assignment (except initialisation), does not occupy storage slot.
- ``constant`` for functions: Same as ``view``.
diff --git a/docs/types.rst b/docs/types.rst
index 9c1c73c6..fb88b006 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -337,7 +337,7 @@ be passed via and returned from external function calls.
Function types are notated as follows::
- function (<parameter types>) {internal|external} [constant|view|payable] [returns (<return types>)]
+ function (<parameter types>) {internal|external} [pure|constant|view|payable] [returns (<return types>)]
In contrast to the parameter types, the return types cannot be empty - if the
function type should not return anything, the whole ``returns (<return types>)``
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index ab1cbb52..2f130414 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -57,6 +57,8 @@ bool StaticAnalyzer::visit(FunctionDefinition const& _function)
solAssert(m_localVarUseCount.empty(), "");
m_nonPayablePublic = _function.isPublic() && !_function.isPayable();
m_constructor = _function.isConstructor();
+ if (_function.stateMutability() == StateMutability::Pure)
+ m_errorReporter.warning(_function.location(), "Function is marked pure. Be careful, pureness is not enforced yet.");
return true;
}
diff --git a/libsolidity/ast/ASTEnums.h b/libsolidity/ast/ASTEnums.h
index f7c75878..5ba21907 100644
--- a/libsolidity/ast/ASTEnums.h
+++ b/libsolidity/ast/ASTEnums.h
@@ -31,12 +31,14 @@ namespace solidity
{
// How a function can mutate the EVM state.
-enum class StateMutability { View, NonPayable, Payable };
+enum class StateMutability { Pure, View, NonPayable, Payable };
inline std::string stateMutabilityToString(StateMutability const& _stateMutability)
{
switch(_stateMutability)
{
+ case StateMutability::Pure:
+ return "pure";
case StateMutability::View:
return "view";
case StateMutability::NonPayable:
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index f1f6770e..c0d635f3 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -325,7 +325,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
std::vector<pair<string, Json::Value>> attributes = {
make_pair("name", _node.name()),
// FIXME: remove with next breaking release
- make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() == StateMutability::View),
+ make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() <= StateMutability::View),
make_pair("payable", _node.isPayable()),
make_pair("statemutability", stateMutabilityToString(_node.stateMutability())),
make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
@@ -418,7 +418,7 @@ bool ASTJsonConverter::visit(FunctionTypeName const& _node)
make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
make_pair("statemutability", stateMutabilityToString(_node.stateMutability())),
// FIXME: remove with next breaking release
- make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() == StateMutability::View),
+ make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() <= StateMutability::View),
make_pair("parameterTypes", toJson(*_node.parameterTypeList())),
make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())),
make_pair("typeDescriptions", typePointerToJson(_node.annotation().type))
diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp
index 6e8563f7..dd56ff6d 100644
--- a/libsolidity/interface/ABI.cpp
+++ b/libsolidity/interface/ABI.cpp
@@ -36,7 +36,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef)
method["type"] = "function";
method["name"] = it.second->declaration().name();
// TODO: deprecate constant in a future release
- method["constant"] = it.second->stateMutability() == StateMutability::View;
+ method["constant"] = it.second->stateMutability() == StateMutability::Pure || it.second->stateMutability() == StateMutability::View;
method["payable"] = it.second->isPayable();
method["statemutability"] = stateMutabilityToString(it.second->stateMutability());
method["inputs"] = formatTypeList(
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index cd0d6157..ddfdb667 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -321,6 +321,8 @@ StateMutability Parser::parseStateMutability(Token::Value _token)
// FIXME: constant should be removed at the next breaking release
else if (_token == Token::View || _token == Token::Constant)
stateMutability = StateMutability::View;
+ else if (_token == Token::Pure)
+ stateMutability = StateMutability::Pure;
else
solAssert(false, "Invalid state mutability specifier.");
m_scanner->next();
diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h
index 3bc52f1d..805fbf5d 100644
--- a/libsolidity/parsing/Token.h
+++ b/libsolidity/parsing/Token.h
@@ -169,6 +169,7 @@ namespace solidity
K(Public, "public", 0) \
K(Pragma, "pragma", 0) \
K(Private, "private", 0) \
+ K(Pure, "pure", 0) \
K(Return, "return", 0) \
K(Returns, "returns", 0) \
K(Storage, "storage", 0) \
@@ -230,7 +231,6 @@ namespace solidity
K(Match, "match", 0) \
K(NullLiteral, "null", 0) \
K(Of, "of", 0) \
- K(Pure, "pure", 0) \
K(Relocatable, "relocatable", 0) \
K(Static, "static", 0) \
K(Switch, "switch", 0) \
@@ -290,7 +290,7 @@ public:
static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; }
static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage; }
- static bool isStateMutabilitySpecifier(Value op) { return op == Constant || op == View || op == Payable; }
+ static bool isStateMutabilitySpecifier(Value op) { return op == Pure || op == Constant || op == View || op == Payable; }
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; }
static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; }
static bool isReservedKeyword(Value op) { return (Abstract <= op && op <= TypeOf); }
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index 12fb1f9c..dd51d926 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -361,6 +361,61 @@ BOOST_AUTO_TEST_CASE(constant_function)
checkInterface(sourceCode, interface);
}
+BOOST_AUTO_TEST_CASE(pure_function)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function foo(uint a, uint b) returns(uint d) { return a + b; }
+ function boo(uint32 a) pure returns(uint b) { return a * 4; }
+ }
+ )";
+
+ char const* interface = R"([
+ {
+ "name": "foo",
+ "constant": false,
+ "payable" : false,
+ "statemutability": "nonpayable",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "a",
+ "type": "uint256"
+ },
+ {
+ "name": "b",
+ "type": "uint256"
+ }
+ ],
+ "outputs": [
+ {
+ "name": "d",
+ "type": "uint256"
+ }
+ ]
+ },
+ {
+ "name": "boo",
+ "constant": true,
+ "payable" : false,
+ "statemutability": "pure",
+ "type": "function",
+ "inputs": [{
+ "name": "a",
+ "type": "uint32"
+ }],
+ "outputs": [
+ {
+ "name": "b",
+ "type": "uint256"
+ }
+ ]
+ }
+ ])";
+
+ checkInterface(sourceCode, interface);
+}
+
BOOST_AUTO_TEST_CASE(events)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index 8e84ead1..a39e0958 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -928,6 +928,16 @@ BOOST_AUTO_TEST_CASE(multiple_statemutability_specifiers)
function f() payable constant {}
})";
CHECK_PARSE_ERROR(text, "State mutability already specified as \"payable\".");
+ text = R"(
+ contract c {
+ function f() pure payable {}
+ })";
+ CHECK_PARSE_ERROR(text, "State mutability already specified as \"pure\".");
+ text = R"(
+ contract c {
+ function f() pure constant {}
+ })";
+ CHECK_PARSE_ERROR(text, "State mutability already specified as \"pure\".");
}
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)