Update common-patterns.rst

This commit is contained in:
Matt Wisniewski 2017-04-19 14:12:45 -04:00 committed by chriseth
parent 00933b99cc
commit 2b4b86aa7f
7 changed files with 73 additions and 99 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;
@ -70,7 +70,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;
@ -86,9 +86,7 @@ This is as opposed to the more intuitive sending pattern:
// Check if call succeeds to prevent an attacker // Check if call succeeds to prevent an attacker
// from trapping the previous person's funds in // from trapping the previous person's funds in
// this contract through a callstack attack // this contract through a callstack attack
if (!richest.send(msg.value)) { richest.transfer(msg.value);
throw;
}
richest = msg.sender; richest = msg.sender;
mostSent = msg.value; mostSent = msg.value;
return true; return true;
@ -135,7 +133,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 +150,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 +166,7 @@ restrictions highly readable.
} }
modifier onlyAfter(uint _time) { modifier onlyAfter(uint _time) {
if (now < _time) throw; require(now >= _time);
_; _;
} }
@ -190,8 +187,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 +272,7 @@ function finishes.
:: ::
pragma solidity ^0.4.0; pragma solidity ^0.4.11;
contract StateMachine { contract StateMachine {
enum Stages { enum Stages {
@ -293,7 +289,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)) assert(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)) require(msg.sender.send(share));
throw;
} }
} }
@ -162,7 +161,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 {
@ -173,8 +172,8 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like
} }
function transfer(address dest, uint amount) { function transfer(address dest, uint amount) {
if (tx.origin != owner) { throw; } require(tx.origin == owner);
if (!dest.call.value(amount)()) throw; require(dest.call.value(amount)());
} }
} }

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,12 @@ 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) { // `throw` terminates and reverts all changes to
// `throw` 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 also consume all provided gas. require(msg.sender == chairperson || !voters[voter].voted);
throw;
}
voters[voter].weight = 1; voters[voter].weight = 1;
} }
@ -102,12 +100,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 +117,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 +140,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 +212,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 +263,16 @@ 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.
throw; require(msg.value <= highestBid);
}
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 +321,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)) require(beneficiary.transfer(highestBid));
throw;
} }
} }
@ -381,7 +372,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 +400,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 +445,11 @@ 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 ||
_fake.length != length || _fake.length == length ||
_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 +470,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 +515,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 +532,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 +544,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 require(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 +580,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.
@ -625,8 +610,7 @@ Safe Remote Purchase
state = State.Inactive; state = State.Inactive;
// This actually allows both the buyer and the seller to // This actually allows both the buyer and the seller to
// block the refund. // block the refund.
if (!buyer.send(value) || !seller.send(this.balance)) require(buyer.transfer(value) || seller.transfer(this.balance));
throw;
} }
} }

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;
} }
} }