mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			375 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			375 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
###############
 | 
						|
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 ``transfer`` call, this is not recommended as it
 | 
						|
introduces a potential security risk. You may read
 | 
						|
more about this on the :ref:`security_considerations` page.
 | 
						|
 | 
						|
The following 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 receive the funds of the person who has gone on to
 | 
						|
become the new richest.
 | 
						|
 | 
						|
::
 | 
						|
 | 
						|
    pragma solidity >0.4.99 <0.6.0;
 | 
						|
 | 
						|
    contract WithdrawalContract {
 | 
						|
        address public richest;
 | 
						|
        uint public mostSent;
 | 
						|
 | 
						|
        mapping (address => uint) pendingWithdrawals;
 | 
						|
 | 
						|
        constructor() public payable {
 | 
						|
            richest = msg.sender;
 | 
						|
            mostSent = msg.value;
 | 
						|
        }
 | 
						|
 | 
						|
        function becomeRichest() public payable returns (bool) {
 | 
						|
            if (msg.value > mostSent) {
 | 
						|
                pendingWithdrawals[richest] += msg.value;
 | 
						|
                richest = msg.sender;
 | 
						|
                mostSent = msg.value;
 | 
						|
                return true;
 | 
						|
            } else {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        function withdraw() public {
 | 
						|
            uint amount = pendingWithdrawals[msg.sender];
 | 
						|
            // Remember to zero the pending refund before
 | 
						|
            // sending to prevent re-entrancy attacks
 | 
						|
            pendingWithdrawals[msg.sender] = 0;
 | 
						|
            msg.sender.transfer(amount);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
This is as opposed to the more intuitive sending pattern:
 | 
						|
 | 
						|
::
 | 
						|
 | 
						|
    pragma solidity >0.4.99 <0.6.0;
 | 
						|
 | 
						|
    contract SendContract {
 | 
						|
        address payable public richest;
 | 
						|
        uint public mostSent;
 | 
						|
 | 
						|
        constructor() public payable {
 | 
						|
            richest = msg.sender;
 | 
						|
            mostSent = msg.value;
 | 
						|
        }
 | 
						|
 | 
						|
        function becomeRichest() public payable returns (bool) {
 | 
						|
            if (msg.value > mostSent) {
 | 
						|
                // This line can cause problems (explained below).
 | 
						|
                richest.transfer(msg.value);
 | 
						|
                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 fails (e.g. by using ``revert()`` or by just
 | 
						|
consuming more than the 2300 gas stipend transferred to them). 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
 | 
						|
 | 
						|
******************
 | 
						|
Restricting Access
 | 
						|
******************
 | 
						|
 | 
						|
Restricting access is a common pattern for contracts.
 | 
						|
Note that you can never restrict any human or computer
 | 
						|
from reading the content of your transactions or
 | 
						|
your contract's state. You can make it a bit harder
 | 
						|
by using encryption, but if your contract is supposed
 | 
						|
to read the data, so will everyone else.
 | 
						|
 | 
						|
You can restrict read access to your contract's state
 | 
						|
by **other contracts**. That is actually the default
 | 
						|
unless you declare make your state variables ``public``.
 | 
						|
 | 
						|
Furthermore, you can restrict who can make modifications
 | 
						|
to your contract's state or call your contract's
 | 
						|
functions and this is what this section is about.
 | 
						|
 | 
						|
.. index:: function;modifier
 | 
						|
 | 
						|
The use of **function modifiers** makes these
 | 
						|
restrictions highly readable.
 | 
						|
 | 
						|
::
 | 
						|
 | 
						|
    pragma solidity >=0.4.22 <0.6.0;
 | 
						|
 | 
						|
    contract AccessRestriction {
 | 
						|
        // These will be assigned at the construction
 | 
						|
        // phase, where `msg.sender` is the account
 | 
						|
        // creating this contract.
 | 
						|
        address public owner = msg.sender;
 | 
						|
        uint public creationTime = now;
 | 
						|
 | 
						|
        // Modifiers can be used to change
 | 
						|
        // the body of a function.
 | 
						|
        // If this modifier is used, it will
 | 
						|
        // prepend a check that only passes
 | 
						|
        // if the function is called from
 | 
						|
        // a certain address.
 | 
						|
        modifier onlyBy(address _account)
 | 
						|
        {
 | 
						|
            require(
 | 
						|
                msg.sender == _account,
 | 
						|
                "Sender not authorized."
 | 
						|
            );
 | 
						|
            // Do not forget the "_;"! It will
 | 
						|
            // be replaced by the actual function
 | 
						|
            // body when the modifier is used.
 | 
						|
            _;
 | 
						|
        }
 | 
						|
 | 
						|
        /// Make `_newOwner` the new owner of this
 | 
						|
        /// contract.
 | 
						|
        function changeOwner(address _newOwner)
 | 
						|
            public
 | 
						|
            onlyBy(owner)
 | 
						|
        {
 | 
						|
            owner = _newOwner;
 | 
						|
        }
 | 
						|
 | 
						|
        modifier onlyAfter(uint _time) {
 | 
						|
            require(
 | 
						|
                now >= _time,
 | 
						|
                "Function called too early."
 | 
						|
            );
 | 
						|
            _;
 | 
						|
        }
 | 
						|
 | 
						|
        /// Erase ownership information.
 | 
						|
        /// May only be called 6 weeks after
 | 
						|
        /// the contract has been created.
 | 
						|
        function disown()
 | 
						|
            public
 | 
						|
            onlyBy(owner)
 | 
						|
            onlyAfter(creationTime + 6 weeks)
 | 
						|
        {
 | 
						|
            delete owner;
 | 
						|
        }
 | 
						|
 | 
						|
        // This modifier requires a certain
 | 
						|
        // fee being associated with a function call.
 | 
						|
        // If the caller sent too much, he or she is
 | 
						|
        // refunded, but only after the function body.
 | 
						|
        // This was dangerous before Solidity version 0.4.0,
 | 
						|
        // where it was possible to skip the part after `_;`.
 | 
						|
        modifier costs(uint _amount) {
 | 
						|
            require(
 | 
						|
                msg.value >= _amount,
 | 
						|
                "Not enough Ether provided."
 | 
						|
            );
 | 
						|
            _;
 | 
						|
            if (msg.value > _amount)
 | 
						|
                msg.sender.transfer(msg.value - _amount);
 | 
						|
        }
 | 
						|
 | 
						|
        function forceOwnerChange(address _newOwner)
 | 
						|
            public
 | 
						|
            payable
 | 
						|
            costs(200 ether)
 | 
						|
        {
 | 
						|
            owner = _newOwner;
 | 
						|
            // just some example condition
 | 
						|
            if (uint(owner) & 0 == 1)
 | 
						|
                // This did not refund for Solidity
 | 
						|
                // before version 0.4.0.
 | 
						|
                return;
 | 
						|
            // refund overpaid fees
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
A more specialised way in which access to function
 | 
						|
calls can be restricted will be discussed
 | 
						|
in the next example.
 | 
						|
 | 
						|
.. index:: state machine
 | 
						|
 | 
						|
*************
 | 
						|
State Machine
 | 
						|
*************
 | 
						|
 | 
						|
Contracts often act as a state machine, which means
 | 
						|
that they have certain **stages** in which they behave
 | 
						|
differently or in which different functions can
 | 
						|
be called. A function call often ends a stage
 | 
						|
and transitions the contract into the next stage
 | 
						|
(especially if the contract models **interaction**).
 | 
						|
It is also common that some stages are automatically
 | 
						|
reached at a certain point in **time**.
 | 
						|
 | 
						|
An example for this is a blind auction contract which
 | 
						|
starts in the stage "accepting blinded bids", then
 | 
						|
transitions to "revealing bids" which is ended by
 | 
						|
"determine auction outcome".
 | 
						|
 | 
						|
.. index:: function;modifier
 | 
						|
 | 
						|
Function modifiers can be used in this situation
 | 
						|
to model the states and guard against
 | 
						|
incorrect usage of the contract.
 | 
						|
 | 
						|
Example
 | 
						|
=======
 | 
						|
 | 
						|
In the following example,
 | 
						|
the modifier ``atStage`` ensures that the function can
 | 
						|
only be called at a certain stage.
 | 
						|
 | 
						|
Automatic timed transitions
 | 
						|
are handled by the modifier ``timeTransitions``, which
 | 
						|
should be used for all functions.
 | 
						|
 | 
						|
.. note::
 | 
						|
    **Modifier Order Matters**.
 | 
						|
    If atStage is combined
 | 
						|
    with timedTransitions, make sure that you mention
 | 
						|
    it after the latter, so that the new stage is
 | 
						|
    taken into account.
 | 
						|
 | 
						|
Finally, the modifier ``transitionNext`` can be used
 | 
						|
to automatically go to the next stage when the
 | 
						|
function finishes.
 | 
						|
 | 
						|
.. note::
 | 
						|
    **Modifier May be Skipped**.
 | 
						|
    This only applies to Solidity before version 0.4.0:
 | 
						|
    Since modifiers are applied by simply replacing
 | 
						|
    code and not by using a function call,
 | 
						|
    the code in the transitionNext modifier
 | 
						|
    can be skipped if the function itself uses
 | 
						|
    return. If you want to do that, make sure
 | 
						|
    to call nextStage manually from those functions.
 | 
						|
    Starting with version 0.4.0, modifier code
 | 
						|
    will run even if the function explicitly returns.
 | 
						|
 | 
						|
::
 | 
						|
 | 
						|
    pragma solidity >=0.4.22 <0.6.0;
 | 
						|
 | 
						|
    contract StateMachine {
 | 
						|
        enum Stages {
 | 
						|
            AcceptingBlindedBids,
 | 
						|
            RevealBids,
 | 
						|
            AnotherStage,
 | 
						|
            AreWeDoneYet,
 | 
						|
            Finished
 | 
						|
        }
 | 
						|
 | 
						|
        // This is the current stage.
 | 
						|
        Stages public stage = Stages.AcceptingBlindedBids;
 | 
						|
 | 
						|
        uint public creationTime = now;
 | 
						|
 | 
						|
        modifier atStage(Stages _stage) {
 | 
						|
            require(
 | 
						|
                stage == _stage,
 | 
						|
                "Function cannot be called at this time."
 | 
						|
            );
 | 
						|
            _;
 | 
						|
        }
 | 
						|
 | 
						|
        function nextStage() internal {
 | 
						|
            stage = Stages(uint(stage) + 1);
 | 
						|
        }
 | 
						|
 | 
						|
        // Perform timed transitions. Be sure to mention
 | 
						|
        // this modifier first, otherwise the guards
 | 
						|
        // will not take the new stage into account.
 | 
						|
        modifier timedTransitions() {
 | 
						|
            if (stage == Stages.AcceptingBlindedBids &&
 | 
						|
                        now >= creationTime + 10 days)
 | 
						|
                nextStage();
 | 
						|
            if (stage == Stages.RevealBids &&
 | 
						|
                    now >= creationTime + 12 days)
 | 
						|
                nextStage();
 | 
						|
            // The other stages transition by transaction
 | 
						|
            _;
 | 
						|
        }
 | 
						|
 | 
						|
        // Order of the modifiers matters here!
 | 
						|
        function bid()
 | 
						|
            public
 | 
						|
            payable
 | 
						|
            timedTransitions
 | 
						|
            atStage(Stages.AcceptingBlindedBids)
 | 
						|
        {
 | 
						|
            // We will not implement that here
 | 
						|
        }
 | 
						|
 | 
						|
        function reveal()
 | 
						|
            public
 | 
						|
            timedTransitions
 | 
						|
            atStage(Stages.RevealBids)
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        // This modifier goes to the next stage
 | 
						|
        // after the function is done.
 | 
						|
        modifier transitionNext()
 | 
						|
        {
 | 
						|
            _;
 | 
						|
            nextStage();
 | 
						|
        }
 | 
						|
 | 
						|
        function g()
 | 
						|
            public
 | 
						|
            timedTransitions
 | 
						|
            atStage(Stages.AnotherStage)
 | 
						|
            transitionNext
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        function h()
 | 
						|
            public
 | 
						|
            timedTransitions
 | 
						|
            atStage(Stages.AreWeDoneYet)
 | 
						|
            transitionNext
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        function i()
 | 
						|
            public
 | 
						|
            timedTransitions
 | 
						|
            atStage(Stages.Finished)
 | 
						|
        {
 | 
						|
        }
 | 
						|
    }
 |