aboutsummaryrefslogtreecommitdiffstats
path: root/docs/common-patterns.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/common-patterns.rst')
-rw-r--r--docs/common-patterns.rst164
1 files changed, 68 insertions, 96 deletions
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst
index 9f5e12c4..870be049 100644
--- a/docs/common-patterns.rst
+++ b/docs/common-patterns.rst
@@ -18,74 +18,57 @@ introduces a potential security risk. You may read
more about this on the :ref:`security_considerations` page.
This is an example of the withdrawal pattern in practice in
-an Ether storage contract.
+an Ether "store" contract.
::
- contract WithdrawalPatternAuction {
- address public beneficiary;
- uint public auctionStart;
- uint public biddingTime;
+ contract WithdrawalStore {
- address public highestBidder;
- uint public highestBid;
-
- mapping(address => uint) pendingReturns;
-
- bool ended;
-
- function WithdrawalPatternAuction(
- uint _biddingTime,
- address _beneficiary
- ) {
- beneficiary = _beneficiary;
- auctionStart = now;
- biddingTime = _biddingTime;
+ struct Item {
+ uint price;
+ uint quantity;
}
- function bid() {
- if (now > auctionStart + biddingTime) {
- throw;
+ modifier onlyOwner {
+ if (msg.sender == owner) {
+ _
}
- if (msg.value <= highestBid) {
+ else {
throw;
}
-
- // Note that funds for unsucessful
- // bids are returned using the
- // pendingReturns mapping
- if (highestBidder != 0) {
- pendingReturns[highestBidder] += highestBid;
- }
- highestBidder = msg.sender;
- highestBid = msg.value;
}
- // Withdraw a bid that was overbid.
- function withdraw() {
- var amount = pendingReturns[msg.sender];
- // It is important to set this to zero because the recipient
- // can call this function again as part of the receiving call
- // before `send` returns.
- pendingReturns[msg.sender] = 0;
- if (!msg.sender.send(amount))
- throw; // If anything fails, this will revert the changes above
- }
+ address owner;
+ mapping (string => Item) inventory;
- function auctionEnd() {
- if (now <= auctionStart + biddingTime)
- throw;
- if (ended)
- throw;
+ function WithdrawalStore() {
+ owner = msg.sender;
+ }
- ended = true;
+ function updateInventory(
+ string _item,
+ uint _price,
+ uint _quantity
+ ) onlyOwner {
+ inventory[_item] = Item(_price, _quantity);
+ }
- if (!beneficiary.send(this.balance))
- throw;
+ // Notice that the owner withdraws their own Ether
+ function withdraw() onlyOwner {
+ owner.send(this.balance);
}
- function () {
- throw;
+ function buy(string _item) returns (bool) {
+ if (
+ inventory[_item].quantity > 0 &&
+ inventory[_item].price <= msg.value
+ ) {
+ inventory[_item].quantity--;
+ return true;
+ }
+ else {
+ return false;
+ }
}
}
@@ -93,66 +76,55 @@ This is as opposed to the more intuitive sending pattern.
::
- contract SendPatternAuction {
- address public beneficiary;
- uint public auctionStart;
- uint public biddingTime;
-
- address public highestBidder;
- uint public highestBid;
+ contract SendStore {
- bool ended;
-
- function WithdrawalPatternAuction(
- uint _biddingTime,
- address _beneficiary
- ) {
- beneficiary = _beneficiary;
- auctionStart = now;
- biddingTime = _biddingTime;
+ struct Item {
+ uint price;
+ uint quantity;
}
- function bid() {
- if (now > auctionStart + biddingTime) {
- throw;
+ modifier onlyOwner {
+ if (msg.sender == owner) {
+ _
}
- if (msg.value <= highestBid) {
+ else {
throw;
}
-
- // Note that funds are
- // immedietally sent back to
- // unsucessful bidders
- if (highestBidder != 0) {
- msg.sender.send(amount);// DANGER - send is unchecked!
- }
- highestBidder = msg.sender;
- highestBid = msg.value;
}
- function auctionEnd() {
- if (now <= auctionStart + biddingTime)
- throw;
- if (ended)
- throw;
+ address owner;
+ mapping (string => Item) inventory;
- ended = true;
+ function SendStore() {
+ owner = msg.sender;
+ }
- if (!beneficiary.send(this.balance))
- throw;
+ function updateInventory(
+ string _item,
+ uint _price,
+ uint _quantity
+ ) onlyOwner {
+ inventory[_item] = Item(_price, _quantity);
}
- function () {
- throw;
+ function buy(string _item) returns (bool) {
+ if (
+ inventory[_item].quantity > 0 &&
+ inventory[_item].price <= msg.value
+ ) {
+ inventory[_item].quantity--;
+ owner.send(msg.value);// WARNING - this send is unchecked!!
+ return true;
+ }
+ else {
+ return false;
+ }
}
}
Notice that, in this example, an attacker could trap
-the previous highest bidder's funds in the contract
-by causing the execution of `send` to fail.
-
-The full auction example can be found at
-:ref:`simple_auction`.
+the owner's funds in the contract by causing the
+execution of `send` to fail through a callstack attack.
.. index:: access;restricting