mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Cleanup to make the docs more consistent.
This commit is contained in:
parent
2b4b86aa7f
commit
7e838fd4a8
@ -52,17 +52,12 @@ become the new richest.
|
||||
}
|
||||
}
|
||||
|
||||
function withdraw() returns (bool) {
|
||||
function withdraw() {
|
||||
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;
|
||||
}
|
||||
msg.sender.transfer(amount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,9 +78,7 @@ This is as opposed to the more intuitive sending pattern:
|
||||
|
||||
function becomeRichest() payable 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
|
||||
// This line can cause problems (explained below).
|
||||
richest.transfer(msg.value);
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
@ -98,12 +91,16 @@ This is as opposed to the more intuitive sending pattern:
|
||||
|
||||
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.
|
||||
the address of a contract that has a fallback function
|
||||
which fails (e.g. by using ``revert()`` or by just
|
||||
conssuming more than the 2300 gas stipend). That way,
|
||||
whenever ``transfer`` is called to deliver funds to the
|
||||
"poisoned" contract, it will fail and thus also ``becomeRichest``
|
||||
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
|
||||
|
||||
|
@ -1034,7 +1034,7 @@ more advanced example to implement a set).
|
||||
// The library functions can be called without a
|
||||
// specific instance of the library, since the
|
||||
// "instance" will be the current contract.
|
||||
assert(Set.insert(knownValues, value));
|
||||
require(Set.insert(knownValues, value));
|
||||
}
|
||||
// In this contract, we can also directly access knownValues.flags, if we want.
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ outlined further below:
|
||||
function withdraw() {
|
||||
var share = shares[msg.sender];
|
||||
shares[msg.sender] = 0;
|
||||
require(msg.sender.send(share));
|
||||
msg.sender.transfer(share);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,22 +123,23 @@ Sending and Receiving Ether
|
||||
(for example in the "details" section in Remix).
|
||||
|
||||
- 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
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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 ``revert`` or
|
||||
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
|
||||
a :ref:`"withdraw" pattern instead of a "send" pattern <withdrawal_pattern>`.
|
||||
|
||||
@ -171,9 +172,9 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function transfer(address dest, uint amount) {
|
||||
function transferTo(address dest, uint amount) {
|
||||
require(tx.origin == owner);
|
||||
require(dest.call.value(amount)());
|
||||
dest.transfer(amount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,7 +192,7 @@ Now someone tricks you into sending ether to the address of this attack wallet:
|
||||
}
|
||||
|
||||
function() {
|
||||
TxUserWallet(msg.sender).transfer(owner, msg.sender.balance);
|
||||
TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,11 +87,13 @@ of votes.
|
||||
// Give `voter` the right to vote on this ballot.
|
||||
// May only be called by `chairperson`.
|
||||
function giveRightToVote(address voter) {
|
||||
// `throw` terminates and reverts all changes to
|
||||
// If the argument of `require` evaluates to `false`,
|
||||
// it terminates and reverts all changes to
|
||||
// the state and to Ether balances. It is often
|
||||
// a good idea to use this if functions are
|
||||
// called incorrectly. But watch out, this
|
||||
// will also consume all provided gas.
|
||||
// will currently also consume all provided gas
|
||||
// (this is planned to change in the future).
|
||||
require(msg.sender == chairperson || !voters[voter].voted);
|
||||
voters[voter].weight = 1;
|
||||
}
|
||||
@ -267,7 +269,6 @@ activate themselves.
|
||||
// Revert the call if the bidding
|
||||
// period is over.
|
||||
require(now < auctionStart + biddingTime);
|
||||
|
||||
|
||||
// If the bid is not higher, send the
|
||||
// money back.
|
||||
@ -329,7 +330,7 @@ activate themselves.
|
||||
AuctionEnded(highestBidder, highestBid);
|
||||
|
||||
// 3. Interaction
|
||||
require(beneficiary.transfer(highestBid));
|
||||
beneficiary.transfer(highestBid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,8 +401,8 @@ high or low invalid bids.
|
||||
/// functions. `onlyBefore` is applied to `bid` below:
|
||||
/// The new function body is the modifier's body where
|
||||
/// `_` is replaced by the old function body.
|
||||
modifier onlyBefore(uint _time) { require(!now >= _time); _; }
|
||||
modifier onlyAfter(uint _time) { require(!now <= _time); _; }
|
||||
modifier onlyBefore(uint _time) { require(now < _time); _; }
|
||||
modifier onlyAfter(uint _time) { require(now > _time); _; }
|
||||
|
||||
function BlindAuction(
|
||||
uint _biddingTime,
|
||||
@ -446,8 +447,8 @@ high or low invalid bids.
|
||||
{
|
||||
uint length = bids[msg.sender].length;
|
||||
require(
|
||||
_values.length == length ||
|
||||
_fake.length == length ||
|
||||
_values.length == length &&
|
||||
_fake.length == length &&
|
||||
_secret.length == length
|
||||
);
|
||||
|
||||
@ -544,10 +545,10 @@ Safe Remote Purchase
|
||||
function Purchase() payable {
|
||||
seller = msg.sender;
|
||||
value = msg.value / 2;
|
||||
require(!2 * value != msg.value);
|
||||
require(2 * value == msg.value);
|
||||
}
|
||||
|
||||
modifier require(bool _condition) {
|
||||
modifier condition(bool _condition) {
|
||||
require(_condition);
|
||||
_;
|
||||
}
|
||||
@ -589,7 +590,7 @@ Safe Remote Purchase
|
||||
/// is called.
|
||||
function confirmPurchase()
|
||||
inState(State.Created)
|
||||
require(msg.value == 2 * value)
|
||||
condition(msg.value == 2 * value)
|
||||
payable
|
||||
{
|
||||
purchaseConfirmed();
|
||||
@ -609,8 +610,9 @@ Safe Remote Purchase
|
||||
// can call in again here.
|
||||
state = State.Inactive;
|
||||
// This actually allows both the buyer and the seller to
|
||||
// block the refund.
|
||||
require(buyer.transfer(value) || seller.transfer(this.balance));
|
||||
// block the refund - the withdraw pattern should be used.
|
||||
buyer.transfer(value);
|
||||
seller.transfer(this.balance));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user