Merge pull request #1702 from ethereum/assertError

Change effect of assert to invalid opcode.
This commit is contained in:
Yoichi Hirai 2017-03-03 18:25:50 +01:00 committed by GitHub
commit cfbbd89daf
5 changed files with 25 additions and 27 deletions

View File

@ -399,10 +399,9 @@ Currently, Solidity automatically generates a runtime exception in the following
While a user-provided exception is generated in the following situations: While a user-provided exception is generated in the following situations:
#. Calling ``throw``. #. Calling ``throw``.
#. The condition of ``assert(condition)`` is not met.
Internally, Solidity performs a revert operation (instruction ``0xfd``) when a user-provided exception is thrown. In contrast, it performs an invalid operation Internally, Solidity performs a revert operation (instruction ``0xfd``) 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 (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 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
did not occur. Because we want to retain the atomicity of transactions, the safest thing to do is to revert all changes and make the whole transaction did not occur. Because we want to retain the atomicity of transactions, the safest thing to do is to revert all changes and make the whole transaction
(or at least call) without effect. (or at least call) without effect.

View File

@ -435,7 +435,7 @@ The following is the order of precedence for operators, listed in order of evalu
| *16* | Comma operator | ``,`` | | *16* | Comma operator | ``,`` |
+------------+-------------------------------------+--------------------------------------------+ +------------+-------------------------------------+--------------------------------------------+
.. index:: block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, now, gas price, origin, assert, revert, 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, revert, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
Global Variables Global Variables
================ ================
@ -461,7 +461,6 @@ 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 - ``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`` - ``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`` - ``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`` - ``this`` (current contract's type): the current contract, explicitly convertible to ``address``
- ``super``: the contract one level higher in the inheritance hierarchy - ``super``: the contract one level higher in the inheritance hierarchy
- ``selfdestruct(address recipient)``: destroy the current contract, sending its funds to the given address - ``selfdestruct(address recipient)``: destroy the current contract, sending its funds to the given address

View File

@ -66,8 +66,9 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared<
make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Location::ECRecover)), make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Location::ECRecover)),
make_shared<MagicVariableDeclaration>("ripemd160", 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", // Disabled until decision about semantics of assert is made.
make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Location::Assert)), // make_shared<MagicVariableDeclaration>("assert",
// make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Location::Assert)),
make_shared<MagicVariableDeclaration>("revert", make_shared<MagicVariableDeclaration>("revert",
make_shared<FunctionType>(strings(), strings(), FunctionType::Location::Revert))}) make_shared<FunctionType>(strings(), strings(), FunctionType::Location::Revert))})
{ {

View File

@ -885,9 +885,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// jump if condition was met // jump if condition was met
m_context << Instruction::ISZERO << Instruction::ISZERO; m_context << Instruction::ISZERO << Instruction::ISZERO;
auto success = m_context.appendConditionalJump(); auto success = m_context.appendConditionalJump();
// condition was not met, abort // condition was not met, flag an error
m_context << u256(0) << u256(0); m_context << Instruction::INVALID;
m_context << Instruction::REVERT;
// the success branch // the success branch
m_context << success; m_context << success;
break; break;

View File

@ -9119,24 +9119,24 @@ BOOST_AUTO_TEST_CASE(invalid_instruction)
BOOST_CHECK(callContractFunction("f()") == encodeArgs()); BOOST_CHECK(callContractFunction("f()") == encodeArgs());
} }
BOOST_AUTO_TEST_CASE(assert) //BOOST_AUTO_TEST_CASE(assert)
{ //{
char const* sourceCode = R"( // char const* sourceCode = R"(
contract C { // contract C {
function f() { // function f() {
assert(false); // assert(false);
} // }
function g(bool val) returns (bool) { // function g(bool val) returns (bool) {
assert(val == true); // assert(val == true);
return true; // return true;
} // }
} // }
)"; // )";
compileAndRun(sourceCode, 0, "C"); // compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("f()") == encodeArgs()); // BOOST_CHECK(callContractFunction("f()") == encodeArgs());
BOOST_CHECK(callContractFunction("g(bool)", false) == encodeArgs()); // BOOST_CHECK(callContractFunction("g(bool)", false) == encodeArgs());
BOOST_CHECK(callContractFunction("g(bool)", true) == encodeArgs(true)); // BOOST_CHECK(callContractFunction("g(bool)", true) == encodeArgs(true));
} //}
BOOST_AUTO_TEST_CASE(revert) BOOST_AUTO_TEST_CASE(revert)
{ {