mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
commit
14ded4963d
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)``:
|
||||
|
@ -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))})
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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."));
|
||||
}
|
||||
|
@ -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()
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user