Update subcurrency example in introductory section

Further updates

Add line breaks

Changes from review

Updates from review

Changes from review

Fix label
This commit is contained in:
Chris Ward 2019-04-23 16:40:43 +10:00
parent 13518820c7
commit 931b93146f
3 changed files with 65 additions and 64 deletions

View File

@ -71,40 +71,41 @@ so that only you can alter the number.
Subcurrency Example
===================
The following contract will implement the simplest form of a
cryptocurrency. It is possible to generate coins out of thin air, but
only the person that created the contract will be able to do that (it is easy
to implement a different issuance scheme).
Furthermore, anyone can send coins to each other without a need for
registering with username and password — all you need is an Ethereum keypair.
The following contract implements the simplest form of a
cryptocurrency. The contract allows only its creator to create new coins (different issuance scheme are possible).
Anyone can send coins to each other without a need for
registering with a username and password, all you need is an Ethereum keypair.
::
pragma solidity >=0.5.0 <0.7.0;
contract Coin {
// The keyword "public" makes those variables
// easily readable from outside.
// The keyword "public" makes variables
// accessible from other contracts
address public minter;
mapping (address => uint) public balances;
// Events allow light clients to react to
// changes efficiently.
// Events allow clients to react to specific
// contract changes you declare
event Sent(address from, address to, uint amount);
// This is the constructor whose code is
// run only when the contract is created.
// Constructor code is only run when the contract
// is created
constructor() public {
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 {
require(msg.sender == minter);
require(amount < 1e60);
balances[receiver] += amount;
}
// Sends an amount of existing coins
// from any caller to an address
function send(address receiver, uint amount) public {
require(amount <= balances[msg.sender], "Insufficient balance.");
balances[msg.sender] -= amount;
@ -115,58 +116,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.
The line ``address public minter;`` declares a state variable of type address
that is publicly accessible. The ``address`` type is a 160-bit value
that does not allow any arithmetic operations. It is suitable for
storing addresses of contracts or of keypairs belonging to external
persons. The keyword ``public`` automatically generates a function that
allows you to access the current value of the state variable
from outside of the contract.
Without this keyword, other contracts have no way to access the variable.
The code of the function generated by the compiler is roughly equivalent
The line ``address public minter;`` declares a state variable of type :ref:`address<address>`.
The ``address`` type is a 160-bit value that does not allow any arithmetic operations.
It is suitable for storing addresses of contracts, or a hash of the public half of a keypair belonging to :ref:`external accounts<accounts>`.
The keyword ``public`` automatically generates a function that allows you to access the current value of the state
variable from outside of the contract. Without this keyword, other contracts have no way to access the variable.
The code of the function generated by the compiler is equivalent
to the following (ignore ``external`` and ``view`` for now)::
function minter() external view returns (address) { return minter; }
Of course, adding a function exactly like that will not work
because we would have a
function and a state variable with the same name, but hopefully, you
get the idea - the compiler figures that out for you.
You could add a function like the above yourself, but you would have a function and state variable with the same name.
You do not need to do this, the compiler figures it out for you.
.. index:: mapping
The next line, ``mapping (address => uint) public balances;`` also
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
virtually initialized 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
too far, though, as it is neither possible to obtain a list of all keys of
a mapping, nor a list of all values. So either keep in mind (or
better, keep a list or use a more advanced data type) what you
added to the mapping or use it in a context where this is not needed.
virtually initialised such that every possible key exists from the start and is mapped to a
value whose byte-representation is all zeros. However, it is neither possible to obtain a list of all keys of
a mapping, nor a list of all values. Record what you
added to the mapping, or use it in a context where this is not needed. Or
even better, keep a list, or use a more suitable data type.
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::
function balances(address _account) external view returns (uint) {
return balances[_account];
}
As you see, you can use this function to easily query the balance of a
single account.
You can use this function to query the balance of a single account.
.. index:: event
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
``send``. User interfaces (as well as server applications of course) can
listen for those events being emitted on the blockchain without much
cost. As soon as it is emitted, the listener will also receive the
arguments ``from``, ``to`` and ``amount``, which makes it easy to track
transactions. In order to listen for this event, you would use the following
JavaScript code (which assumes that ``Coin`` is a contract object created via
web3.js or a similar module)::
an :ref:`"event" <events>`, which is emitted in the last line of the function
``send``. Ethereum clients such as web applications can
listen for these events emitted on the blockchain without much
cost. As soon as it is emitted, the listener receives the
arguments ``from``, ``to`` and ``amount``, which makes it possible to track
transactions.
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) {
if (!error) {
@ -179,36 +178,33 @@ web3.js or a similar module)::
}
})
Note how the automatically generated function ``balances`` is called from
the user interface.
.. index:: coin
The constructor is a special function which is run during creation of the contract and
cannot be called afterwards. It permanently stores the address of the person creating the
contract: ``msg`` (together with ``tx`` and ``block``) is a special global variable that
contains some properties which allow access to the blockchain. ``msg.sender`` is
The :ref:`constructor<constructor>` is a special function run during the creation of the contract and
cannot be called afterwards. In this case, it permanently stores the address of the person creating the
contract. The ``msg`` variable (together with ``tx`` and ``block``) is a
: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.
Finally, the functions that will actually end up with the contract and can be called
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.
The functions that make up the contract, and that users and contracts can call are ``mint`` and ``send``.
On the other hand, ``send`` can be used by anyone (who already
has some of these coins) to send coins to anyone else. If you do not have
enough coins to send, the ``require`` call will fail and also provide the
user with an appropriate error message string.
The ``mint`` function sends an amount of newly created coins to another address.
The :ref:`require <assert-and-require>` function call defines conditions that reverts all changes if not met.
In this example, ``require(msg.sender == minter);`` ensures that only the creator of the contract can call ``mint``,
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::
If you use
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
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,
but you have to inspect the coin contract address and not the addresses of the
coin owners.
@ -302,6 +298,8 @@ Smart contracts even have limited access to other smart contracts.
.. index:: ! account, address, storage, balance
.. _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.
.. index:: ! uint, ! int, ! integer
.. _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
===============================