Skip to content

Commit 14ded49

Browse files
authored
Merge pull request ethereum#1678 from ethereum/assert
Implement assert()
2 parents 885b6ed + fd7ffed commit 14ded49

File tree

8 files changed

+44
-6
lines changed

8 files changed

+44
-6
lines changed

Changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
### 0.4.10 (unreleased)
22

33
Features:
4+
* Add ``assert(condition)``, which throws if condition is false.
45
* Type system: Support explicit conversion of external function to address.
56

67
Bugfixes:

docs/control-structures.rst

+4
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,10 @@ Currently, Solidity automatically generates a runtime exception in the following
396396
#. If your contract receives Ether via a public getter function.
397397
#. If you call a zero-initialized variable of internal function type.
398398

399+
While a user-provided exception is generated in the following situations:
400+
#. Calling ``throw``.
401+
#. The condition of ``assert(condition)`` is not met.
402+
399403
Internally, Solidity performs an "invalid jump" when a user-provided exception is thrown. In contrast, it performs an invalid operation
400404
(instruction ``0xfe``) if a runtime exception is encountered. In both cases, this causes
401405
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

docs/miscellaneous.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ The following is the order of precedence for operators, listed in order of evalu
435435
| *16* | Comma operator | ``,`` |
436436
+------------+-------------------------------------+--------------------------------------------+
437437

438-
.. 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
438+
.. 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
439439

440440
Global Variables
441441
================
@@ -460,6 +460,7 @@ Global Variables
460460
- ``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
461461
- ``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``
462462
- ``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``
463+
- ``assert(bool condition)``: throws if the condition is false
463464
- ``this`` (current contract's type): the current contract, explicitly convertible to ``address``
464465
- ``super``: the contract one level higher in the inheritance hierarchy
465466
- ``selfdestruct(address recipient)``: destroy the current contract, sending its funds to the given address

docs/units-and-global-variables.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ Block and Transaction Properties
7979
You can only access the hashes of the most recent 256 blocks, all other
8080
values will be zero.
8181

82-
.. index:: keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
82+
.. index:: assert, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
8383

8484
Mathematical and Cryptographic Functions
8585
----------------------------------------
8686

87+
``assert(bool condition)``:
88+
throws if the condition is not met.
8789
``addmod(uint x, uint y, uint k) returns (uint)``:
8890
compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``.
8991
``mulmod(uint x, uint y, uint k) returns (uint)``:

libsolidity/analysis/GlobalContext.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared<
6565
make_shared<MagicVariableDeclaration>("ecrecover",
6666
make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Location::ECRecover)),
6767
make_shared<MagicVariableDeclaration>("ripemd160",
68-
make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Location::RIPEMD160, true))})
68+
make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Location::RIPEMD160, true)),
69+
make_shared<MagicVariableDeclaration>("assert",
70+
make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Location::Assert))})
6971
{
7072
}
7173

libsolidity/ast/Types.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -819,8 +819,8 @@ class FunctionType: public Type
819819
{
820820
Internal, ///< stack-call using plain JUMP
821821
External, ///< external call using CALL
822-
CallCode, ///< extercnal call using CALLCODE, i.e. not exchanging the storage
823-
DelegateCall, ///< extercnal call using DELEGATECALL, i.e. not exchanging the storage
822+
CallCode, ///< external call using CALLCODE, i.e. not exchanging the storage
823+
DelegateCall, ///< external call using DELEGATECALL, i.e. not exchanging the storage
824824
Bare, ///< CALL without function hash
825825
BareCallCode, ///< CALLCODE without function hash
826826
BareDelegateCall, ///< DELEGATECALL without function hash
@@ -844,7 +844,8 @@ class FunctionType: public Type
844844
MulMod, ///< MULMOD
845845
ArrayPush, ///< .push() to a dynamically sized array in storage
846846
ByteArrayPush, ///< .push() to a dynamically sized byte array in storage
847-
ObjectCreation ///< array creation using new
847+
ObjectCreation, ///< array creation using new
848+
Assert ///< assert()
848849
};
849850

850851
virtual Category category() const override { return Category::Function; }

libsolidity/codegen/ExpressionCompiler.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,14 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
863863
m_context << Instruction::POP;
864864
break;
865865
}
866+
case Location::Assert:
867+
{
868+
arguments.front()->accept(*this);
869+
utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), false);
870+
m_context << Instruction::ISZERO;
871+
m_context.appendConditionalJumpTo(m_context.errorTag());
872+
break;
873+
}
866874
default:
867875
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid function type."));
868876
}

test/libsolidity/SolidityEndToEndTest.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -9077,6 +9077,25 @@ BOOST_AUTO_TEST_CASE(invalid_instruction)
90779077
BOOST_CHECK(callContractFunction("f()") == encodeArgs());
90789078
}
90799079

9080+
BOOST_AUTO_TEST_CASE(assert)
9081+
{
9082+
char const* sourceCode = R"(
9083+
contract C {
9084+
function f() {
9085+
assert(false);
9086+
}
9087+
function g(bool val) returns (bool) {
9088+
assert(val == true);
9089+
return true;
9090+
}
9091+
}
9092+
)";
9093+
compileAndRun(sourceCode, 0, "C");
9094+
BOOST_CHECK(callContractFunction("f()") == encodeArgs());
9095+
BOOST_CHECK(callContractFunction("g(bool)", false) == encodeArgs());
9096+
BOOST_CHECK(callContractFunction("g(bool)", true) == encodeArgs(true));
9097+
}
9098+
90809099
BOOST_AUTO_TEST_SUITE_END()
90819100

90829101
}

0 commit comments

Comments
 (0)