Merge pull request #2207 from ethereum/wski-develop

chore(Docs): Replaced instances if - throw to require() where applicable.
This commit is contained in:
chriseth 2017-05-03 12:28:16 +02:00 committed by GitHub
commit 4af0451d16
7 changed files with 102 additions and 127 deletions

View File

@ -28,7 +28,7 @@ become the new richest.
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract WithdrawalContract { contract WithdrawalContract {
address public richest; address public richest;
@ -52,17 +52,12 @@ become the new richest.
} }
} }
function withdraw() returns (bool) { function withdraw() {
uint amount = pendingWithdrawals[msg.sender]; uint amount = pendingWithdrawals[msg.sender];
// Remember to zero the pending refund before // Remember to zero the pending refund before
// sending to prevent re-entrancy attacks // sending to prevent re-entrancy attacks
pendingWithdrawals[msg.sender] = 0; pendingWithdrawals[msg.sender] = 0;
if (msg.sender.send(amount)) { msg.sender.transfer(amount);
return true;
} else {
pendingWithdrawals[msg.sender] = amount;
return false;
}
} }
} }
@ -70,7 +65,7 @@ This is as opposed to the more intuitive sending pattern:
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract SendContract { contract SendContract {
address public richest; address public richest;
@ -83,12 +78,8 @@ This is as opposed to the more intuitive sending pattern:
function becomeRichest() payable returns (bool) { function becomeRichest() payable returns (bool) {
if (msg.value > mostSent) { if (msg.value > mostSent) {
// Check if call succeeds to prevent an attacker // This line can cause problems (explained below).
// from trapping the previous person's funds in richest.transfer(msg.value);
// this contract through a callstack attack
if (!richest.send(msg.value)) {
throw;
}
richest = msg.sender; richest = msg.sender;
mostSent = msg.value; mostSent = msg.value;
return true; return true;
@ -100,12 +91,16 @@ This is as opposed to the more intuitive sending pattern:
Notice that, in this example, an attacker could trap the Notice that, in this example, an attacker could trap the
contract into an unusable state by causing ``richest`` to be contract into an unusable state by causing ``richest`` to be
the address of a contract that has a fallback function the address of a contract that has a fallback function
which consumes more than the 2300 gas stipend. That way, which fails (e.g. by using ``revert()`` or by just
whenever ``send`` is called to deliver funds to the conssuming more than the 2300 gas stipend). That way,
"poisoned" contract, it will cause execution to always fail whenever ``transfer`` is called to deliver funds to the
because there will not be enough gas to finish the execution "poisoned" contract, it will fail and thus also ``becomeRichest``
of the fallback function. will fail, with the contract being stuck forever.
In contrast, if you use the "withdraw" pattern from the first example,
the attacker can only cause his or her own withdraw to fail and not the
rest of the contract's workings.
.. index:: access;restricting .. index:: access;restricting
@ -135,7 +130,7 @@ restrictions highly readable.
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract AccessRestriction { contract AccessRestriction {
// These will be assigned at the construction // These will be assigned at the construction
@ -152,8 +147,7 @@ restrictions highly readable.
// a certain address. // a certain address.
modifier onlyBy(address _account) modifier onlyBy(address _account)
{ {
if (msg.sender != _account) require(msg.sender == _account);
throw;
// 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.
@ -169,7 +163,7 @@ restrictions highly readable.
} }
modifier onlyAfter(uint _time) { modifier onlyAfter(uint _time) {
if (now < _time) throw; require(now >= _time);
_; _;
} }
@ -190,8 +184,7 @@ 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) {
if (msg.value < _amount) require(msg.value >= _amount);
throw;
_; _;
if (msg.value > _amount) if (msg.value > _amount)
msg.sender.send(msg.value - _amount); msg.sender.send(msg.value - _amount);
@ -276,7 +269,7 @@ function finishes.
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract StateMachine { contract StateMachine {
enum Stages { enum Stages {
@ -293,7 +286,7 @@ function finishes.
uint public creationTime = now; uint public creationTime = now;
modifier atStage(Stages _stage) { modifier atStage(Stages _stage) {
if (stage != _stage) throw; require(stage == _stage);
_; _;
} }

View File

@ -327,7 +327,7 @@ inheritable properties of contracts and may be overridden by derived contracts.
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract owned { contract owned {
function owned() { owner = msg.sender; } function owned() { owner = msg.sender; }
@ -341,8 +341,7 @@ 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 {
if (msg.sender != owner) require(msg.sender == owner);
throw;
_; _;
} }
} }
@ -390,7 +389,7 @@ inheritable properties of contracts and may be overridden by derived contracts.
contract Mutex { contract Mutex {
bool locked; bool locked;
modifier noReentrancy() { modifier noReentrancy() {
if (locked) throw; require(!locked);
locked = true; locked = true;
_; _;
locked = false; locked = false;
@ -401,7 +400,7 @@ inheritable properties of contracts and may be overridden by derived contracts.
/// The `return 7` statement assigns 7 to the return value but still /// The `return 7` statement assigns 7 to the return value but still
/// executes the statement `locked = false` in the modifier. /// executes the statement `locked = false` in the modifier.
function f() noReentrancy returns (uint) { function f() noReentrancy returns (uint) {
if (!msg.sender.call()) throw; require(msg.sender.call());
return 7; return 7;
} }
} }
@ -989,7 +988,7 @@ more advanced example to implement a set).
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
library Set { library Set {
// We define a new struct datatype that will be used to // We define a new struct datatype that will be used to
@ -1035,8 +1034,7 @@ more advanced example to implement a set).
// The library functions can be called without a // The library functions can be called without a
// specific instance of the library, since the // specific instance of the library, since the
// "instance" will be the current contract. // "instance" will be the current contract.
if (!Set.insert(knownValues, value)) require(Set.insert(knownValues, value));
throw;
} }
// In this contract, we can also directly access knownValues.flags, if we want. // In this contract, we can also directly access knownValues.flags, if we want.
} }
@ -1166,7 +1164,7 @@ available without having to add further code.
Let us rewrite the set example from the Let us rewrite the set example from the
:ref:`libraries` in this way:: :ref:`libraries` in this way::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
// This is the same code as before, just without comments // This is the same code as before, just without comments
library Set { library Set {
@ -1207,8 +1205,7 @@ Let us rewrite the set example from the
// corresponding member functions. // corresponding member functions.
// The following function call is identical to // The following function call is identical to
// Set.insert(knownValues, value) // Set.insert(knownValues, value)
if (!knownValues.insert(value)) require(knownValues.insert(value));
throw;
} }
} }

View File

@ -665,8 +665,7 @@ What does the following strange check do in the Custom Token contract?
:: ::
if (balanceOf[_to] + _value < balanceOf[_to]) require((balanceOf[_to] + _value) >= balanceOf[_to]);
throw;
Integers in Solidity (and most other machine-related programming languages) are restricted to a certain range. Integers in Solidity (and most other machine-related programming languages) are restricted to a certain range.
For ``uint256``, this is ``0`` up to ``2**256 - 1``. If the result of some operation on those numbers For ``uint256``, this is ``0`` up to ``2**256 - 1``. If the result of some operation on those numbers

View File

@ -79,7 +79,7 @@ outlined further below:
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract Fund { contract Fund {
/// Mapping of ether shares of the contract. /// Mapping of ether shares of the contract.
@ -88,8 +88,7 @@ outlined further below:
function withdraw() { function withdraw() {
var share = shares[msg.sender]; var share = shares[msg.sender];
shares[msg.sender] = 0; shares[msg.sender] = 0;
if (!msg.sender.send(share)) msg.sender.transfer(share);
throw;
} }
} }
@ -124,22 +123,24 @@ Sending and Receiving Ether
(for example in the "details" section in Remix). (for example in the "details" section in Remix).
- There is a way to forward more gas to the receiving contract using - There is a way to forward more gas to the receiving contract using
``addr.call.value(x)()``. This is essentially the same as ``addr.send(x)``, ``addr.call.value(x)()``. This is essentially the same as ``addr.transfer(x)``,
only that it forwards all remaining gas and opens up the ability for the only that it forwards all remaining gas and opens up the ability for the
recipient to perform more expensive actions. This might include calling back recipient to perform more expensive actions (and it only returns a failure code
and does not automatically propagate the error). This might include calling back
into the sending contract or other state changes you might not have thought of. into the sending contract or other state changes you might not have thought of.
So it allows for great flexibility for honest users but also for malicious actors. So it allows for great flexibility for honest users but also for malicious actors.
- If you want to send Ether using ``address.send``, there are certain details to be aware of: - If you want to send Ether using ``address.transfer``, there are certain details to be aware of:
1. If the recipient is a contract, it causes its fallback function to be executed which can, in turn, call back the sending contract. 1. If the recipient is a contract, it causes its fallback function to be executed which can, in turn, call back the sending contract.
2. Sending Ether can fail due to the call depth going above 1024. Since the caller is in total control of the call 2. Sending Ether can fail due to the call depth going above 1024. Since the caller is in total control of the call
depth, they can force the transfer to fail; make sure to always check the return value of ``send``. Better yet, depth, they can force the transfer to fail; take this possibility into account or use ``send`` and make sure to always check its return value. Better yet,
write your contract using a pattern where the recipient can withdraw Ether instead. write your contract using a pattern where the recipient can withdraw Ether instead.
3. Sending Ether can also fail because the execution of the recipient contract 3. Sending Ether can also fail because the execution of the recipient contract
requires more than the allotted amount of gas (explicitly by using ``throw`` or requires more than the allotted amount of gas (explicitly by using ``require``,
``assert``, ``revert``, ``throw`` or
because the operation is just too expensive) - it "runs out of gas" (OOG). because the operation is just too expensive) - it "runs out of gas" (OOG).
If the return value of ``send`` is checked, this might provide a If you use ``transfer`` or ``send`` with a return value check, this might provide a
means for the recipient to block progress in the sending contract. Again, the best practice here is to use means for the recipient to block progress in the sending contract. Again, the best practice here is to use
a :ref:`"withdraw" pattern instead of a "send" pattern <withdrawal_pattern>`. a :ref:`"withdraw" pattern instead of a "send" pattern <withdrawal_pattern>`.
@ -162,7 +163,7 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE // THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract TxUserWallet { contract TxUserWallet {
@ -172,9 +173,9 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like
owner = msg.sender; owner = msg.sender;
} }
function transfer(address dest, uint amount) { function transferTo(address dest, uint amount) {
if (tx.origin != owner) { throw; } require(tx.origin == owner);
if (!dest.call.value(amount)()) throw; dest.transfer(amount);
} }
} }
@ -192,7 +193,7 @@ Now someone tricks you into sending ether to the address of this attack wallet:
} }
function() { function() {
TxUserWallet(msg.sender).transfer(owner, msg.sender.balance); TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);
} }
} }

View File

@ -36,7 +36,7 @@ of votes.
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
/// @title Voting with delegation. /// @title Voting with delegation.
contract Ballot { contract Ballot {
@ -87,14 +87,14 @@ 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) { function giveRightToVote(address voter) {
if (msg.sender != chairperson || voters[voter].voted) { // If the argument of `require` evaluates to `false`,
// `throw` terminates and reverts all changes to // it terminates and reverts all changes to
// the state and to Ether balances. It is often // the state and to Ether balances. It is often
// a good idea to use this if functions are // a good idea to use this if functions are
// called incorrectly. But watch out, this // called incorrectly. But watch out, this
// will also consume all provided gas. // will currently also consume all provided gas
throw; // (this is planned to change in the future).
} require((msg.sender == chairperson) && !voters[voter].voted);
voters[voter].weight = 1; voters[voter].weight = 1;
} }
@ -102,12 +102,10 @@ of votes.
function delegate(address to) { function delegate(address to) {
// assigns reference // assigns reference
Voter sender = voters[msg.sender]; Voter sender = voters[msg.sender];
if (sender.voted) require(!sender.voted);
throw;
// Self-delegation is not allowed. // Self-delegation is not allowed.
if (to == msg.sender) require(to != msg.sender);
throw;
// Forward the delegation as long as // Forward the delegation as long as
// `to` also delegated. // `to` also delegated.
@ -121,8 +119,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.
if (to == msg.sender) require(to != msg.sender);
throw;
} }
// Since `sender` is a reference, this // Since `sender` is a reference, this
@ -145,8 +142,7 @@ of votes.
/// to proposal `proposals[proposal].name`. /// to proposal `proposals[proposal].name`.
function vote(uint proposal) { function vote(uint proposal) {
Voter sender = voters[msg.sender]; Voter sender = voters[msg.sender];
if (sender.voted) require(!sender.voted);
throw;
sender.voted = true; sender.voted = true;
sender.vote = proposal; sender.vote = proposal;
@ -218,7 +214,7 @@ activate themselves.
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract SimpleAuction { contract SimpleAuction {
// Parameters of the auction. Times are either // Parameters of the auction. Times are either
@ -269,16 +265,15 @@ activate themselves.
// the transaction. The keyword payable // the transaction. The keyword payable
// is required for the function to // is required for the function to
// be able to receive Ether. // be able to receive Ether.
if (now > auctionStart + biddingTime) {
// Revert the call if the bidding // Revert the call if the bidding
// period is over. // period is over.
throw; require(now <= (auctionStart + biddingTime));
}
if (msg.value <= highestBid) { // If the bid is not higher, send the
// If the bid is not higher, send the // money back.
// money back. require(msg.value > highestBid);
throw;
}
if (highestBidder != 0) { if (highestBidder != 0) {
// Sending back the money by simply using // Sending back the money by simply using
// highestBidder.send(highestBid) is a security risk // highestBidder.send(highestBid) is a security risk
@ -327,18 +322,15 @@ activate themselves.
// external contracts. // external contracts.
// 1. Conditions // 1. Conditions
if (now <= auctionStart + biddingTime) require(now >= (auctionStart + biddingTime)); // auction did not yet end
throw; // auction did not yet end require(!ended); // this function has already been called
if (ended)
throw; // this function has already been called
// 2. Effects // 2. Effects
ended = true; ended = true;
AuctionEnded(highestBidder, highestBid); AuctionEnded(highestBidder, highestBid);
// 3. Interaction // 3. Interaction
if (!beneficiary.send(highestBid)) beneficiary.transfer(highestBid);
throw;
} }
} }
@ -381,7 +373,7 @@ high or low invalid bids.
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract BlindAuction { contract BlindAuction {
struct Bid { struct Bid {
@ -409,8 +401,8 @@ high or low invalid bids.
/// functions. `onlyBefore` is applied to `bid` below: /// functions. `onlyBefore` is applied to `bid` below:
/// The new function body is the modifier's body where /// The new function body is the modifier's body where
/// `_` is replaced by the old function body. /// `_` is replaced by the old function body.
modifier onlyBefore(uint _time) { if (now >= _time) throw; _; } modifier onlyBefore(uint _time) { require(now < _time); _; }
modifier onlyAfter(uint _time) { if (now <= _time) throw; _; } modifier onlyAfter(uint _time) { require(now > _time); _; }
function BlindAuction( function BlindAuction(
uint _biddingTime, uint _biddingTime,
@ -454,13 +446,9 @@ high or low invalid bids.
onlyBefore(revealEnd) onlyBefore(revealEnd)
{ {
uint length = bids[msg.sender].length; uint length = bids[msg.sender].length;
if ( require(_values.length == length);
_values.length != length || require(_fake.length == length);
_fake.length != length || require(_secret.length == length);
_secret.length != length
) {
throw;
}
uint refund; uint refund;
for (uint i = 0; i < length; i++) { for (uint i = 0; i < length; i++) {
@ -481,8 +469,7 @@ high or low invalid bids.
// the same deposit. // the same deposit.
bid.blindedBid = 0; bid.blindedBid = 0;
} }
if (!msg.sender.send(refund)) msg.sender.transfer(refund);
throw;
} }
// This is an "internal" function which means that it // This is an "internal" function which means that it
@ -527,14 +514,12 @@ high or low invalid bids.
function auctionEnd() function auctionEnd()
onlyAfter(revealEnd) onlyAfter(revealEnd)
{ {
if (ended) require(!ended);
throw;
AuctionEnded(highestBidder, highestBid); AuctionEnded(highestBidder, highestBid);
ended = true; ended = true;
// We send all the money we have, because some // We send all the money we have, because some
// of the refunds might have failed. // of the refunds might have failed.
if (!beneficiary.send(this.balance)) beneficiary.transfer(this.balance);
throw;
} }
} }
@ -546,7 +531,7 @@ Safe Remote Purchase
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract Purchase { contract Purchase {
uint public value; uint public value;
@ -558,26 +543,26 @@ Safe Remote Purchase
function Purchase() payable { function Purchase() payable {
seller = msg.sender; seller = msg.sender;
value = msg.value / 2; value = msg.value / 2;
if (2 * value != msg.value) throw; require((2 * value) == msg.value);
} }
modifier require(bool _condition) { modifier condition(bool _condition) {
if (!_condition) throw; require(_condition);
_; _;
} }
modifier onlyBuyer() { modifier onlyBuyer() {
if (msg.sender != buyer) throw; require(msg.sender == buyer);
_; _;
} }
modifier onlySeller() { modifier onlySeller() {
if (msg.sender != seller) throw; require(msg.sender == seller);
_; _;
} }
modifier inState(State _state) { modifier inState(State _state) {
if (state != _state) throw; require(state == _state);
_; _;
} }
@ -594,8 +579,7 @@ Safe Remote Purchase
{ {
aborted(); aborted();
state = State.Inactive; state = State.Inactive;
if (!seller.send(this.balance)) seller.transfer(this.balance);
throw;
} }
/// Confirm the purchase as buyer. /// Confirm the purchase as buyer.
@ -604,7 +588,7 @@ Safe Remote Purchase
/// is called. /// is called.
function confirmPurchase() function confirmPurchase()
inState(State.Created) inState(State.Created)
require(msg.value == 2 * value) condition(msg.value == (2 * value))
payable payable
{ {
purchaseConfirmed(); purchaseConfirmed();
@ -623,10 +607,12 @@ Safe Remote Purchase
// otherwise, the contracts called using `send` below // otherwise, the contracts called using `send` below
// can call in again here. // can call in again here.
state = State.Inactive; state = State.Inactive;
// This actually allows both the buyer and the seller to
// block the refund. // NOTE: This actually allows both the buyer and the seller to
if (!buyer.send(value) || !seller.send(this.balance)) // block the refund - the withdraw pattern should be used.
throw;
buyer.transfer(value);
seller.transfer(this.balance));
} }
} }

View File

@ -62,13 +62,13 @@ Function modifiers can be used to amend the semantics of functions in a declarat
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract Purchase { contract Purchase {
address public seller; address public seller;
modifier onlySeller() { // Modifier modifier onlySeller() { // Modifier
if (msg.sender != seller) throw; require(msg.sender == seller);
_; _;
} }

View File

@ -420,7 +420,7 @@ Example that shows how to use internal function types::
Another example that uses external function types:: Another example that uses external function types::
pragma solidity ^0.4.5; pragma solidity ^0.4.11;
contract Oracle { contract Oracle {
struct Request { struct Request {
@ -445,7 +445,7 @@ Another example that uses external function types::
oracle.query("USD", this.oracleResponse); oracle.query("USD", this.oracleResponse);
} }
function oracleResponse(bytes response) { function oracleResponse(bytes response) {
if (msg.sender != address(oracle)) throw; require(msg.sender == address(oracle));
// Use the data // Use the data
} }
} }
@ -722,7 +722,7 @@ shown in the following example:
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract CrowdFunding { contract CrowdFunding {
// Defines a new type with two fields. // Defines a new type with two fields.
@ -763,8 +763,7 @@ shown in the following example:
return false; return false;
uint amount = c.amount; uint amount = c.amount;
c.amount = 0; c.amount = 0;
if (!c.beneficiary.send(amount)) c.beneficiary.transfer(amount);
throw;
return true; return true;
} }
} }