mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6567 from ethereum/docs-intro-subcurrency
[DOCS] Update subcurrency example in introductory section
This commit is contained in:
commit
9c5dc63ed2
@ -70,40 +70,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;
|
||||
@ -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.
|
||||
|
||||
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) {
|
||||
@ -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
|
||||
|
||||
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.
|
||||
@ -301,6 +297,8 @@ Smart contracts even have limited access to other smart contracts.
|
||||
|
||||
.. index:: ! account, address, storage, balance
|
||||
|
||||
.. _accounts:
|
||||
|
||||
Accounts
|
||||
========
|
||||
|
||||
|
@ -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
|
||||
--------
|
||||
|
@ -52,6 +52,8 @@ interpret a function parameter in days, you can in the following way::
|
||||
}
|
||||
}
|
||||
|
||||
.. _special-variables-functions:
|
||||
|
||||
Special Variables and Functions
|
||||
===============================
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user