mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #706 from Denton-L/withdrawal-pattern
Add Withdrawal Pattern Example
This commit is contained in:
commit
0d736fde6d
@ -2,6 +2,110 @@
|
||||
Common Patterns
|
||||
###############
|
||||
|
||||
.. index:: withdrawal
|
||||
|
||||
.. _withdrawal_pattern:
|
||||
|
||||
*************************
|
||||
Withdrawal from Contracts
|
||||
*************************
|
||||
|
||||
The recommended method of sending funds after an effect
|
||||
is using the withdrawal pattern. Although the most intuitive
|
||||
method of sending Ether, as a result of an effect, is a
|
||||
direct ``send`` call, this is not recommended as it
|
||||
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
|
||||
a contract where the goal is to send the most money to the
|
||||
contract in order to become the "richest", inspired by
|
||||
`King of the Ether <https://www.kingoftheether.com/>`_.
|
||||
|
||||
In the following contract, if you are usurped as the richest,
|
||||
you will recieve the funds of the person who has gone on to
|
||||
become the new richest.
|
||||
|
||||
::
|
||||
|
||||
contract WithdrawalContract {
|
||||
address public richest;
|
||||
uint public mostSent;
|
||||
|
||||
mapping (address => uint) pendingWithdrawals;
|
||||
|
||||
function WithdrawalContract() {
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
}
|
||||
|
||||
function becomeRichest() returns (bool) {
|
||||
if (msg.value > mostSent) {
|
||||
pendingWithdrawals[richest] += msg.value;
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function withdraw() returns (bool) {
|
||||
uint amount = pendingWithdrawals[msg.sender];
|
||||
// Remember to zero the pending refund before
|
||||
// sending to prevent re-entrancy attacks
|
||||
pendingWithdrawals[msg.sender] = 0;
|
||||
if (msg.sender.send(amount)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
pendingWithdrawals[msg.sender] = amount;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
This is as opposed to the more intuitive sending pattern.
|
||||
|
||||
::
|
||||
|
||||
contract SendContract {
|
||||
address public richest;
|
||||
uint public mostSent;
|
||||
|
||||
function SendContract() {
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
}
|
||||
|
||||
function becomeRichest() returns (bool) {
|
||||
if (msg.value > mostSent) {
|
||||
// Check if call succeeds to prevent an attacker
|
||||
// from trapping the previous person's funds in
|
||||
// this contract through a callstack attack
|
||||
if (!richest.send(msg.value)) {
|
||||
throw;
|
||||
}
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Notice that, in this example, an attacker could trap the
|
||||
contract into an unusable state by causing ``richest`` to be
|
||||
the address of a contract that has a fallback function
|
||||
which consumes more than the 2300 gas stipend. That way,
|
||||
whenever ``send`` is called to deliver funds to the
|
||||
"poisoned" contract, it will cause execution to always fail
|
||||
because there will not be enough gas to finish the execution
|
||||
of the fallback function.
|
||||
|
||||
.. index:: access;restricting
|
||||
|
||||
******************
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _security_considerations:
|
||||
|
||||
#######################
|
||||
Security Considerations
|
||||
#######################
|
||||
@ -124,7 +126,7 @@ Sending and Receiving Ether
|
||||
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
|
||||
means for the recipient to block progress in the sending contract. Again, the best practice here is to use
|
||||
a "withdraw" pattern instead of a "send" pattern.
|
||||
a :ref:`"withdraw" pattern instead of a "send" pattern <withdrawal_pattern>`.
|
||||
|
||||
Callstack Depth
|
||||
===============
|
||||
|
@ -191,6 +191,8 @@ contract into a blind auction where it is not
|
||||
possible to see the actual bid until the bidding
|
||||
period ends.
|
||||
|
||||
.. _simple_auction:
|
||||
|
||||
Simple Open Auction
|
||||
===================
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user