aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md1
-rw-r--r--docs/control-structures.rst4
-rw-r--r--docs/miscellaneous.rst3
-rw-r--r--docs/units-and-global-variables.rst4
-rw-r--r--libsolidity/analysis/GlobalContext.cpp4
-rw-r--r--libsolidity/ast/Types.h7
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp8
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp19
8 files changed, 44 insertions, 6 deletions
diff --git a/Changelog.md b/Changelog.md
index 0c4e8329..d383ba42 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,6 +1,7 @@
### 0.4.10 (unreleased)
Features:
+ * Add ``assert(condition)``, which throws if condition is false.
* Type system: Support explicit conversion of external function to address.
Bugfixes:
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index 1c7d71f2..ff0a48ec 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -396,6 +396,10 @@ Currently, Solidity automatically generates a runtime exception in the following
#. If your contract receives Ether via a public getter function.
#. If you call a zero-initialized variable of internal function type.
+While a user-provided exception is generated in the following situations:
+#. Calling ``throw``.
+#. The condition of ``assert(condition)`` is not met.
+
Internally, Solidity performs an "invalid jump" when a user-provided exception is thrown. In contrast, it performs an invalid operation
(instruction ``0xfe``) if a runtime exception is encountered. In both cases, this causes
the EVM to revert all changes made to the state. The reason for this is that there is no safe way to continue execution, because an expected effect
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index 47650067..a64ceeb2 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -435,7 +435,7 @@ The following is the order of precedence for operators, listed in order of evalu
| *16* | Comma operator | ``,`` |
+------------+-------------------------------------+--------------------------------------------+
-.. index:: block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, now, gas price, origin, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
+.. index:: block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, now, gas price, origin, assert, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
Global Variables
================
@@ -460,6 +460,7 @@ Global Variables
- ``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``: recover address associated with the public key from elliptic curve signature, return zero on error
- ``addmod(uint x, uint y, uint k) returns (uint)``: compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``
- ``mulmod(uint x, uint y, uint k) returns (uint)``: compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``
+- ``assert(bool condition)``: throws if the condition is false
- ``this`` (current contract's type): the current contract, explicitly convertible to ``address``
- ``super``: the contract one level higher in the inheritance hierarchy
- ``selfdestruct(address recipient)``: destroy the current contract, sending its funds to the given address
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index dd3d4be8..a6f6613f 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -79,11 +79,13 @@ Block and Transaction Properties
You can only access the hashes of the most recent 256 blocks, all other
values will be zero.
-.. index:: keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
+.. index:: assert, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
Mathematical and Cryptographic Functions
----------------------------------------
+``assert(bool condition)``:
+ throws if the condition is not met.
``addmod(uint x, uint y, uint k) returns (uint)``:
compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``.
``mulmod(uint x, uint y, uint k) returns (uint)``:
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp
index e46868be..cc418c5e 100644
--- a/libsolidity/analysis/GlobalContext.cpp
+++ b/libsolidity/analysis/GlobalContext.cpp
@@ -65,7 +65,9 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared<
make_shared<MagicVariableDeclaration>("ecrecover",
make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Location::ECRecover)),
make_shared<MagicVariableDeclaration>("ripemd160",
- make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Location::RIPEMD160, true))})
+ make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Location::RIPEMD160, true)),
+ make_shared<MagicVariableDeclaration>("assert",
+ make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Location::Assert))})
{
}
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index e280b32c..83d840e0 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -819,8 +819,8 @@ public:
{
Internal, ///< stack-call using plain JUMP
External, ///< external call using CALL
- CallCode, ///< extercnal call using CALLCODE, i.e. not exchanging the storage
- DelegateCall, ///< extercnal call using DELEGATECALL, i.e. not exchanging the storage
+ CallCode, ///< external call using CALLCODE, i.e. not exchanging the storage
+ DelegateCall, ///< external call using DELEGATECALL, i.e. not exchanging the storage
Bare, ///< CALL without function hash
BareCallCode, ///< CALLCODE without function hash
BareDelegateCall, ///< DELEGATECALL without function hash
@@ -844,7 +844,8 @@ public:
MulMod, ///< MULMOD
ArrayPush, ///< .push() to a dynamically sized array in storage
ByteArrayPush, ///< .push() to a dynamically sized byte array in storage
- ObjectCreation ///< array creation using new
+ ObjectCreation, ///< array creation using new
+ Assert ///< assert()
};
virtual Category category() const override { return Category::Function; }
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index d74d9dd3..f69d61db 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -863,6 +863,14 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << Instruction::POP;
break;
}
+ case Location::Assert:
+ {
+ arguments.front()->accept(*this);
+ utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), false);
+ m_context << Instruction::ISZERO;
+ m_context.appendConditionalJumpTo(m_context.errorTag());
+ break;
+ }
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid function type."));
}
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 4924b55d..e49db34e 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -9077,6 +9077,25 @@ BOOST_AUTO_TEST_CASE(invalid_instruction)
BOOST_CHECK(callContractFunction("f()") == encodeArgs());
}
+BOOST_AUTO_TEST_CASE(assert)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() {
+ assert(false);
+ }
+ function g(bool val) returns (bool) {
+ assert(val == true);
+ return true;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("g(bool)", false) == encodeArgs());
+ BOOST_CHECK(callContractFunction("g(bool)", true) == encodeArgs(true));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}