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
|
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
|
||||||
========
|
========
|
||||||
|
|
||||||
|
@ -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
|
||||||
--------
|
--------
|
||||||
|
@ -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
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user