From 344a388d4461abd7369ea44b123f5afe549dc8f7 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 3 Jan 2018 15:30:01 +0100 Subject: Update documentation. --- docs/common-patterns.rst | 20 ++++++++--- docs/contracts.rst | 10 ++++-- docs/control-structures.rst | 16 ++++++--- docs/miscellaneous.rst | 3 +- docs/solidity-by-example.rst | 66 ++++++++++++++++++++++++------------- docs/structure-of-a-contract.rst | 5 ++- docs/types.rst | 5 ++- docs/units-and-global-variables.rst | 2 ++ 8 files changed, 92 insertions(+), 35 deletions(-) diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index c62b5aca..233bdc4e 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -147,7 +147,10 @@ restrictions highly readable. // a certain address. modifier onlyBy(address _account) { - require(msg.sender == _account); + require( + msg.sender == _account, + "Sender not authorized." + ); // Do not forget the "_;"! It will // be replaced by the actual function // body when the modifier is used. @@ -164,7 +167,10 @@ restrictions highly readable. } modifier onlyAfter(uint _time) { - require(now >= _time); + require( + now >= _time, + "Function called too early." + ); _; } @@ -186,7 +192,10 @@ restrictions highly readable. // This was dangerous before Solidity version 0.4.0, // where it was possible to skip the part after `_;`. modifier costs(uint _amount) { - require(msg.value >= _amount); + require( + msg.value >= _amount, + "Not enough Ether provided." + ); _; if (msg.value > _amount) msg.sender.send(msg.value - _amount); @@ -290,7 +299,10 @@ function finishes. uint public creationTime = now; modifier atStage(Stages _stage) { - require(stage == _stage); + require( + stage == _stage, + "Function cannot be called at this time." + ); _; } diff --git a/docs/contracts.rst b/docs/contracts.rst index 0dd9845c..0c697dd6 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -315,7 +315,10 @@ inheritable properties of contracts and may be overridden by derived contracts. // function is executed and otherwise, an exception is // thrown. modifier onlyOwner { - require(msg.sender == owner); + require( + msg.sender == owner, + "Only owner can call this function." + ); _; } } @@ -360,7 +363,10 @@ inheritable properties of contracts and may be overridden by derived contracts. contract Mutex { bool locked; modifier noReentrancy() { - require(!locked); + require( + !locked, + "Reentrant call." + ); locked = true; _; locked = false; diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 18a02572..7e3027a0 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -472,13 +472,16 @@ of an exception instead of "bubbling up". Catching exceptions is not yet possible. In the following example, you can see how ``require`` can be used to easily check conditions on inputs -and how ``assert`` can be used for internal error checking:: +and how ``assert`` can be used for internal error checking. Note that you can optionally provide +a message string for require, but not for assert. + +:: pragma solidity ^0.4.0; contract Sharer { function sendHalf(address addr) public payable returns (uint balance) { - require(msg.value % 2 == 0); // Only allow even numbers + require(msg.value % 2 == 0, "Even value required."); uint balanceBeforeTransfer = this.balance; addr.transfer(msg.value / 2); // Since transfer throws an exception on failure and @@ -517,7 +520,7 @@ did not occur. Because we want to retain the atomicity of transactions, the safe (or at least call) without effect. Note that ``assert``-style exceptions consume all gas available to the call, while ``require``-style exceptions will not consume any gas starting from the Metropolis release. -The following example shows how an error string can be used together with revert: +The following example shows how an error string can be used together with revert and require: :: @@ -527,13 +530,18 @@ The following example shows how an error string can be used together with revert function buy(uint amount) payable { if (amount > msg.value / 2 ether) revert("Not enough Ether provided."); + // Alternative way to do it: + require( + amount <= msg.value / 2 ether, + "Not enough Ether provided." + ); // Perform the purchase. } } The provided string will be abi-encoded together with a uint value that will always be zero. This means that if a string ``x`` is provided, ``(0, x)`` will be encoded as if a function with arguments -``(uint256, string)`` would be called. This zero is used as a version identifier. Future extensions +``(uint256, string)`` was called. This zero is used as a version identifier. Future extensions of this feature might provide actual exception payload of dynamic type and this number could be used to encode the type or also as a simple numeric error code. Until this is specified, a zero will be used in all cases. \ No newline at end of file diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index c5178b51..8270727f 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -333,8 +333,9 @@ Global Variables - ``tx.origin`` (``address``): sender of the transaction (full call chain) - ``assert(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for internal error) - ``require(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component) +- ``require(bool condition, string message)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component). Also provide error message. - ``revert()``: abort execution and revert state changes -- ``revert(string)``: abort execution and revert state changes providing an explanatory string +- ``revert(string message)``: abort execution and revert state changes providing an explanatory string - ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks - ``keccak256(...) returns (bytes32)``: compute the Ethereum-SHA-3 (Keccak-256) hash of the :ref:`(tightly packed) arguments ` - ``sha3(...) returns (bytes32)``: an alias to ``keccak256`` diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 3636a332..3cbfcd66 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -87,17 +87,25 @@ of votes. // Give `voter` the right to vote on this ballot. // May only be called by `chairperson`. function giveRightToVote(address voter) public { - // If the argument of `require` evaluates to `false`, - // it terminates and reverts all changes to - // the state and to Ether balances. - // This consumes all gas in old EVM versions, but not anymore. - // It is often a good idea to use this if functions are - // called incorrectly. + // If the first argument of `require` evaluates + // to `false`, execution terminates and all + // changes to the state and to Ether balances + // are reverted. + // This used to consume all gas in old EVM versions, but + // not anymore. + // It is often a good idea to use `require` to check if + // functions are called correctly. + // As a second argument, you can also provide an + // explanation about what went wrong. require( - (msg.sender == chairperson) && - !voters[voter].voted && - (voters[voter].weight == 0) + msg.sender == chairperson, + "Only chairperson can give right to vote." ); + require( + !voters[voter].voted, + "The voter already voted." + ); + require(voters[voter].weight == 0); voters[voter].weight = 1; } @@ -105,10 +113,9 @@ of votes. function delegate(address to) public { // assigns reference Voter storage sender = voters[msg.sender]; - require(!sender.voted); + require(!sender.voted, "You already voted."); - // Self-delegation is not allowed. - require(to != msg.sender); + require(to != msg.sender, "Self-delegation is disallowed."); // Forward the delegation as long as // `to` also delegated. @@ -122,7 +129,7 @@ of votes. to = voters[to].delegate; // We found a loop in the delegation, not allowed. - require(to != msg.sender); + require(to != msg.sender, "Found loop in delegation."); } // Since `sender` is a reference, this @@ -145,7 +152,7 @@ of votes. /// to proposal `proposals[proposal].name`. function vote(uint proposal) public { Voter storage sender = voters[msg.sender]; - require(!sender.voted); + require(!sender.voted, "Already voted."); sender.voted = true; sender.vote = proposal; @@ -270,11 +277,17 @@ activate themselves. // Revert the call if the bidding // period is over. - require(now <= auctionEnd); + require( + now <= auctionEnd, + "Auction already ended." + ); // If the bid is not higher, send the // money back. - require(msg.value > highestBid); + require( + msg.value > highestBid, + "There already is a higher bid." + ); if (highestBid != 0) { // Sending back the money by simply using @@ -324,8 +337,8 @@ activate themselves. // external contracts. // 1. Conditions - require(now >= auctionEnd); // auction did not yet end - require(!ended); // this function has already been called + require(now >= auctionEnd, "Auction not yet ended."); + require(!ended, "auctionEnd has already been called."); // 2. Effects ended = true; @@ -543,7 +556,7 @@ Safe Remote Purchase function Purchase() public payable { seller = msg.sender; value = msg.value / 2; - require((2 * value) == msg.value); + require((2 * value) == msg.value, "Value has to be even."); } modifier condition(bool _condition) { @@ -552,17 +565,26 @@ Safe Remote Purchase } modifier onlyBuyer() { - require(msg.sender == buyer); + require( + msg.sender == buyer, + "Only buyer can call this." + ); _; } modifier onlySeller() { - require(msg.sender == seller); + require( + msg.sender == seller, + "Only seller can call this." + ); _; } modifier inState(State _state) { - require(state == _state); + require( + state == _state, + "Invalid state." + ); _; } diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst index df40b1d0..9e5eacbb 100644 --- a/docs/structure-of-a-contract.rst +++ b/docs/structure-of-a-contract.rst @@ -68,7 +68,10 @@ Function modifiers can be used to amend the semantics of functions in a declarat address public seller; modifier onlySeller() { // Modifier - require(msg.sender == seller); + require( + msg.sender == seller, + "Only seller can call this." + ); _; } diff --git a/docs/types.rst b/docs/types.rst index 5de6d07e..07421bdf 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -495,7 +495,10 @@ Another example that uses external function types:: oracle.query("USD", this.oracleResponse); } function oracleResponse(bytes response) public { - require(msg.sender == address(oracle)); + require( + msg.sender == address(oracle), + "Only oracle can call this." + ); // Use the data } } diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index aad00ba2..9d5821d5 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -99,6 +99,8 @@ Error Handling throws if the condition is not met - to be used for internal errors. ``require(bool condition)``: throws if the condition is not met - to be used for errors in inputs or external components. +``require(bool condition, string message)``: + throws if the condition is not met - to be used for errors in inputs or external components. Also provides an error message. ``revert()``: abort execution and revert state changes ``revert(string reason)``: -- cgit v1.2.3