Update documentation.

This commit is contained in:
chriseth 2018-01-03 15:30:01 +01:00
parent aa715f8759
commit 344a388d44
8 changed files with 92 additions and 35 deletions

View File

@ -147,7 +147,10 @@ restrictions highly readable.
// a certain address. // a certain address.
modifier onlyBy(address _account) modifier onlyBy(address _account)
{ {
require(msg.sender == _account); require(
msg.sender == _account,
"Sender not authorized."
);
// Do not forget the "_;"! It will // Do not forget the "_;"! It will
// be replaced by the actual function // be replaced by the actual function
// body when the modifier is used. // body when the modifier is used.
@ -164,7 +167,10 @@ restrictions highly readable.
} }
modifier onlyAfter(uint _time) { 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, // This was dangerous before Solidity version 0.4.0,
// where it was possible to skip the part after `_;`. // where it was possible to skip the part after `_;`.
modifier costs(uint _amount) { modifier costs(uint _amount) {
require(msg.value >= _amount); require(
msg.value >= _amount,
"Not enough Ether provided."
);
_; _;
if (msg.value > _amount) if (msg.value > _amount)
msg.sender.send(msg.value - _amount); msg.sender.send(msg.value - _amount);
@ -290,7 +299,10 @@ function finishes.
uint public creationTime = now; uint public creationTime = now;
modifier atStage(Stages _stage) { modifier atStage(Stages _stage) {
require(stage == _stage); require(
stage == _stage,
"Function cannot be called at this time."
);
_; _;
} }

View File

@ -315,7 +315,10 @@ inheritable properties of contracts and may be overridden by derived contracts.
// function is executed and otherwise, an exception is // function is executed and otherwise, an exception is
// thrown. // thrown.
modifier onlyOwner { 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 { contract Mutex {
bool locked; bool locked;
modifier noReentrancy() { modifier noReentrancy() {
require(!locked); require(
!locked,
"Reentrant call."
);
locked = true; locked = true;
_; _;
locked = false; locked = false;

View File

@ -472,13 +472,16 @@ of an exception instead of "bubbling up".
Catching exceptions is not yet possible. Catching exceptions is not yet possible.
In the following example, you can see how ``require`` can be used to easily check conditions on inputs 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; pragma solidity ^0.4.0;
contract Sharer { contract Sharer {
function sendHalf(address addr) public payable returns (uint balance) { 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; uint balanceBeforeTransfer = this.balance;
addr.transfer(msg.value / 2); addr.transfer(msg.value / 2);
// Since transfer throws an exception on failure and // 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 (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. ``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 { function buy(uint amount) payable {
if (amount > msg.value / 2 ether) if (amount > msg.value / 2 ether)
revert("Not enough Ether provided."); revert("Not enough Ether provided.");
// Alternative way to do it:
require(
amount <= msg.value / 2 ether,
"Not enough Ether provided."
);
// Perform the purchase. // Perform the purchase.
} }
} }
The provided string will be abi-encoded together with a uint value that will always be zero. 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 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 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 to encode the type or also as a simple numeric error code. Until this is specified, a zero will
be used in all cases. be used in all cases.

View File

@ -333,8 +333,9 @@ Global Variables
- ``tx.origin`` (``address``): sender of the transaction (full call chain) - ``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) - ``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)``: 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()``: 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 - ``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 <abi_packed_mode>` - ``keccak256(...) returns (bytes32)``: compute the Ethereum-SHA-3 (Keccak-256) hash of the :ref:`(tightly packed) arguments <abi_packed_mode>`
- ``sha3(...) returns (bytes32)``: an alias to ``keccak256`` - ``sha3(...) returns (bytes32)``: an alias to ``keccak256``

View File

@ -87,17 +87,25 @@ of votes.
// Give `voter` the right to vote on this ballot. // Give `voter` the right to vote on this ballot.
// May only be called by `chairperson`. // May only be called by `chairperson`.
function giveRightToVote(address voter) public { function giveRightToVote(address voter) public {
// If the argument of `require` evaluates to `false`, // If the first argument of `require` evaluates
// it terminates and reverts all changes to // to `false`, execution terminates and all
// the state and to Ether balances. // changes to the state and to Ether balances
// This consumes all gas in old EVM versions, but not anymore. // are reverted.
// It is often a good idea to use this if functions are // This used to consume all gas in old EVM versions, but
// called incorrectly. // 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( require(
(msg.sender == chairperson) && msg.sender == chairperson,
!voters[voter].voted && "Only chairperson can give right to vote."
(voters[voter].weight == 0)
); );
require(
!voters[voter].voted,
"The voter already voted."
);
require(voters[voter].weight == 0);
voters[voter].weight = 1; voters[voter].weight = 1;
} }
@ -105,10 +113,9 @@ of votes.
function delegate(address to) public { function delegate(address to) public {
// assigns reference // assigns reference
Voter storage sender = voters[msg.sender]; Voter storage sender = voters[msg.sender];
require(!sender.voted); require(!sender.voted, "You already voted.");
// Self-delegation is not allowed. require(to != msg.sender, "Self-delegation is disallowed.");
require(to != msg.sender);
// Forward the delegation as long as // Forward the delegation as long as
// `to` also delegated. // `to` also delegated.
@ -122,7 +129,7 @@ of votes.
to = voters[to].delegate; to = voters[to].delegate;
// We found a loop in the delegation, not allowed. // 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 // Since `sender` is a reference, this
@ -145,7 +152,7 @@ of votes.
/// to proposal `proposals[proposal].name`. /// to proposal `proposals[proposal].name`.
function vote(uint proposal) public { function vote(uint proposal) public {
Voter storage sender = voters[msg.sender]; Voter storage sender = voters[msg.sender];
require(!sender.voted); require(!sender.voted, "Already voted.");
sender.voted = true; sender.voted = true;
sender.vote = proposal; sender.vote = proposal;
@ -270,11 +277,17 @@ activate themselves.
// Revert the call if the bidding // Revert the call if the bidding
// period is over. // period is over.
require(now <= auctionEnd); require(
now <= auctionEnd,
"Auction already ended."
);
// If the bid is not higher, send the // If the bid is not higher, send the
// money back. // money back.
require(msg.value > highestBid); require(
msg.value > highestBid,
"There already is a higher bid."
);
if (highestBid != 0) { if (highestBid != 0) {
// Sending back the money by simply using // Sending back the money by simply using
@ -324,8 +337,8 @@ activate themselves.
// external contracts. // external contracts.
// 1. Conditions // 1. Conditions
require(now >= auctionEnd); // auction did not yet end require(now >= auctionEnd, "Auction not yet ended.");
require(!ended); // this function has already been called require(!ended, "auctionEnd has already been called.");
// 2. Effects // 2. Effects
ended = true; ended = true;
@ -543,7 +556,7 @@ Safe Remote Purchase
function Purchase() public payable { function Purchase() public payable {
seller = msg.sender; seller = msg.sender;
value = msg.value / 2; value = msg.value / 2;
require((2 * value) == msg.value); require((2 * value) == msg.value, "Value has to be even.");
} }
modifier condition(bool _condition) { modifier condition(bool _condition) {
@ -552,17 +565,26 @@ Safe Remote Purchase
} }
modifier onlyBuyer() { modifier onlyBuyer() {
require(msg.sender == buyer); require(
msg.sender == buyer,
"Only buyer can call this."
);
_; _;
} }
modifier onlySeller() { modifier onlySeller() {
require(msg.sender == seller); require(
msg.sender == seller,
"Only seller can call this."
);
_; _;
} }
modifier inState(State _state) { modifier inState(State _state) {
require(state == _state); require(
state == _state,
"Invalid state."
);
_; _;
} }

View File

@ -68,7 +68,10 @@ Function modifiers can be used to amend the semantics of functions in a declarat
address public seller; address public seller;
modifier onlySeller() { // Modifier modifier onlySeller() { // Modifier
require(msg.sender == seller); require(
msg.sender == seller,
"Only seller can call this."
);
_; _;
} }

View File

@ -495,7 +495,10 @@ Another example that uses external function types::
oracle.query("USD", this.oracleResponse); oracle.query("USD", this.oracleResponse);
} }
function oracleResponse(bytes response) public { function oracleResponse(bytes response) public {
require(msg.sender == address(oracle)); require(
msg.sender == address(oracle),
"Only oracle can call this."
);
// Use the data // Use the data
} }
} }

View File

@ -99,6 +99,8 @@ Error Handling
throws if the condition is not met - to be used for internal errors. throws if the condition is not met - to be used for internal errors.
``require(bool condition)``: ``require(bool condition)``:
throws if the condition is not met - to be used for errors in inputs or external components. 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()``: ``revert()``:
abort execution and revert state changes abort execution and revert state changes
``revert(string reason)``: ``revert(string reason)``: