Merge pull request #6567 from ethereum/docs-intro-subcurrency

[DOCS] Update subcurrency example in introductory section
This commit is contained in:
chriseth 2019-06-17 10:44:33 +02:00 committed by GitHub
commit 9c5dc63ed2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 64 deletions

View File

@ -70,40 +70,41 @@ so that only you can alter the number.
Subcurrency Example Subcurrency Example
=================== ===================
The following contract will implement the simplest form of a The following contract implements the simplest form of a
cryptocurrency. It is possible to generate coins out of thin air, but cryptocurrency. The contract allows only its creator to create new coins (different issuance scheme are possible).
only the person that created the contract will be able to do that (it is easy Anyone can send coins to each other without a need for
to implement a different issuance scheme). registering with a username and password, all you need is an Ethereum keypair.
Furthermore, anyone can send coins to each other without a need for
registering with username and password — all you need is an Ethereum keypair.
:: ::
pragma solidity >=0.5.0 <0.7.0; pragma solidity >=0.5.0 <0.7.0;
contract Coin { contract Coin {
// The keyword "public" makes those variables // The keyword "public" makes variables
// easily readable from outside. // accessible from other contracts
address public minter; address public minter;
mapping (address => uint) public balances; mapping (address => uint) public balances;
// Events allow light clients to react to // Events allow clients to react to specific
// changes efficiently. // contract changes you declare
event Sent(address from, address to, uint amount); event Sent(address from, address to, uint amount);
// This is the constructor whose code is // Constructor code is only run when the contract
// run only when the contract is created. // is created
constructor() public { constructor() public {
minter = msg.sender; minter = msg.sender;
} }
// Sends an amount of newly created coins to an address
// Can only be called by the contract creator
function mint(address receiver, uint amount) public { function mint(address receiver, uint amount) public {
require(msg.sender == minter); require(msg.sender == minter);
require(amount < 1e60); require(amount < 1e60);
balances[receiver] += amount; balances[receiver] += amount;
} }
// Sends an amount of existing coins
// from any caller to an address
function send(address receiver, uint amount) public { function send(address receiver, uint amount) public {
require(amount <= balances[msg.sender], "Insufficient balance."); require(amount <= balances[msg.sender], "Insufficient balance.");
balances[msg.sender] -= amount; balances[msg.sender] -= amount;
@ -114,58 +115,56 @@ registering with username and password — all you need is an Ethereum keypair.
This contract introduces some new concepts, let us go through them one by one. This contract introduces some new concepts, let us go through them one by one.
The line ``address public minter;`` declares a state variable of type address The line ``address public minter;`` declares a state variable of type :ref:`address<address>`.
that is publicly accessible. The ``address`` type is a 160-bit value The ``address`` type is a 160-bit value that does not allow any arithmetic operations.
that does not allow any arithmetic operations. It is suitable for It is suitable for storing addresses of contracts, or a hash of the public half of a keypair belonging to :ref:`external accounts<accounts>`.
storing addresses of contracts or of keypairs belonging to external
persons. The keyword ``public`` automatically generates a function that The keyword ``public`` automatically generates a function that allows you to access the current value of the state
allows you to access the current value of the state variable variable from outside of the contract. Without this keyword, other contracts have no way to access the variable.
from outside of the contract. The code of the function generated by the compiler is equivalent
Without this keyword, other contracts have no way to access the variable.
The code of the function generated by the compiler is roughly equivalent
to the following (ignore ``external`` and ``view`` for now):: to the following (ignore ``external`` and ``view`` for now)::
function minter() external view returns (address) { return minter; } function minter() external view returns (address) { return minter; }
Of course, adding a function exactly like that will not work You could add a function like the above yourself, but you would have a function and state variable with the same name.
because we would have a You do not need to do this, the compiler figures it out for you.
function and a state variable with the same name, but hopefully, you
get the idea - the compiler figures that out for you.
.. index:: mapping .. index:: mapping
The next line, ``mapping (address => uint) public balances;`` also The next line, ``mapping (address => uint) public balances;`` also
creates a public state variable, but it is a more complex datatype. creates a public state variable, but it is a more complex datatype.
The type maps addresses to unsigned integers. The :ref:`mapping <mapping-types>` type maps addresses to :ref:`unsigned integers <integers>`.
Mappings can be seen as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_ which are Mappings can be seen as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_ which are
virtually initialized such that every possible key exists from the start and is mapped to a virtually initialised such that every possible key exists from the start and is mapped to a
value whose byte-representation is all zeros. This analogy does not go value whose byte-representation is all zeros. However, it is neither possible to obtain a list of all keys of
too far, though, as it is neither possible to obtain a list of all keys of a mapping, nor a list of all values. Record what you
a mapping, nor a list of all values. So either keep in mind (or added to the mapping, or use it in a context where this is not needed. Or
better, keep a list or use a more advanced data type) what you even better, keep a list, or use a more suitable data type.
added to the mapping or use it in a context where this is not needed.
The :ref:`getter function<getter-functions>` created by the ``public`` keyword The :ref:`getter function<getter-functions>` created by the ``public`` keyword
is a bit more complex in this case. It roughly looks like the is more complex in the case of a mapping. It looks like the
following:: following::
function balances(address _account) external view returns (uint) { function balances(address _account) external view returns (uint) {
return balances[_account]; return balances[_account];
} }
As you see, you can use this function to easily query the balance of a You can use this function to query the balance of a single account.
single account.
.. index:: event .. index:: event
The line ``event Sent(address from, address to, uint amount);`` declares The line ``event Sent(address from, address to, uint amount);`` declares
a so-called "event" which is emitted in the last line of the function an :ref:`"event" <events>`, which is emitted in the last line of the function
``send``. User interfaces (as well as server applications of course) can ``send``. Ethereum clients such as web applications can
listen for those events being emitted on the blockchain without much listen for these events emitted on the blockchain without much
cost. As soon as it is emitted, the listener will also receive the cost. As soon as it is emitted, the listener receives the
arguments ``from``, ``to`` and ``amount``, which makes it easy to track arguments ``from``, ``to`` and ``amount``, which makes it possible to track
transactions. In order to listen for this event, you would use the following transactions.
JavaScript code (which assumes that ``Coin`` is a contract object created via
web3.js or a similar module):: To listen for this event, you could use the following
JavaScript code, which uses `web3.js <https://github.com/ethereum/web3.js/>`_ to create the ``Coin`` contract object,
and any user interface calls the automatically generated ``balances`` function from aboves::
Coin.Sent().watch({}, '', function(error, result) { Coin.Sent().watch({}, '', function(error, result) {
if (!error) { if (!error) {
@ -178,36 +177,33 @@ web3.js or a similar module)::
} }
}) })
Note how the automatically generated function ``balances`` is called from
the user interface.
.. index:: coin .. index:: coin
The constructor is a special function which is run during creation of the contract and The :ref:`constructor<constructor>` is a special function run during the creation of the contract and
cannot be called afterwards. It permanently stores the address of the person creating the cannot be called afterwards. In this case, it permanently stores the address of the person creating the
contract: ``msg`` (together with ``tx`` and ``block``) is a special global variable that contract. The ``msg`` variable (together with ``tx`` and ``block``) is a
contains some properties which allow access to the blockchain. ``msg.sender`` is :ref:`special global variable <special-variables-functions>` that
contains properties which allow access to the blockchain. ``msg.sender`` is
always the address where the current (external) function call came from. always the address where the current (external) function call came from.
Finally, the functions that will actually end up with the contract and can be called The functions that make up the contract, and that users and contracts can call are ``mint`` and ``send``.
by users and contracts alike are ``mint`` and ``send``.
If ``mint`` is called by anyone except the account that created the contract,
nothing will happen. This is ensured by the special function ``require`` which
causes all changes to be reverted if its argument evaluates to false.
The second call to ``require`` ensures that there will not be too many coins,
which could cause overflow errors later.
On the other hand, ``send`` can be used by anyone (who already The ``mint`` function sends an amount of newly created coins to another address.
has some of these coins) to send coins to anyone else. If you do not have The :ref:`require <assert-and-require>` function call defines conditions that reverts all changes if not met.
enough coins to send, the ``require`` call will fail and also provide the In this example, ``require(msg.sender == minter);`` ensures that only the creator of the contract can call ``mint``,
user with an appropriate error message string. and ``require(amount < 1e60);`` ensures a maximum amount of tokens, without which could cause overflow errors in the future.
The ``send`` function can be used by anyone (who already
has some of these coins) to send coins to anyone else. If the sender does not have
enough coins to send, the ``require`` call fails and provides the
sender with an appropriate error message string.
.. note:: .. note::
If you use If you use
this contract to send coins to an address, you will not see anything when you this contract to send coins to an address, you will not see anything when you
look at that address on a blockchain explorer, because the fact that you sent look at that address on a blockchain explorer, because the record that you sent
coins and the changed balances are only stored in the data storage of this coins and the changed balances are only stored in the data storage of this
particular coin contract. By the use of events it is relatively easy to create particular coin contract. By using events, you can create
a "blockchain explorer" that tracks transactions and balances of your new coin, a "blockchain explorer" that tracks transactions and balances of your new coin,
but you have to inspect the coin contract address and not the addresses of the but you have to inspect the coin contract address and not the addresses of the
coin owners. coin owners.
@ -301,6 +297,8 @@ Smart contracts even have limited access to other smart contracts.
.. index:: ! account, address, storage, balance .. index:: ! account, address, storage, balance
.. _accounts:
Accounts Accounts
======== ========

View File

@ -26,6 +26,7 @@ Operators:
The operators ``||`` and ``&&`` apply the common short-circuiting rules. This means that in the expression ``f(x) || g(y)``, if ``f(x)`` evaluates to ``true``, ``g(y)`` will not be evaluated even if it may have side-effects. The operators ``||`` and ``&&`` apply the common short-circuiting rules. This means that in the expression ``f(x) || g(y)``, if ``f(x)`` evaluates to ``true``, ``g(y)`` will not be evaluated even if it may have side-effects.
.. index:: ! uint, ! int, ! integer .. index:: ! uint, ! int, ! integer
.. _integers:
Integers Integers
-------- --------

View File

@ -52,6 +52,8 @@ interpret a function parameter in days, you can in the following way::
} }
} }
.. _special-variables-functions:
Special Variables and Functions Special Variables and Functions
=============================== ===============================