aboutsummaryrefslogtreecommitdiffstats
path: root/docs/introduction-to-smart-contracts.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/introduction-to-smart-contracts.rst')
-rw-r--r--docs/introduction-to-smart-contracts.rst124
1 files changed, 70 insertions, 54 deletions
diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst
index d1789c44..7de0d19b 100644
--- a/docs/introduction-to-smart-contracts.rst
+++ b/docs/introduction-to-smart-contracts.rst
@@ -33,14 +33,14 @@ Storage
The first line simply tells that the source code is written for
Solidity version 0.4.0 or anything newer that does not break functionality
(up to, but not including, version 0.5.0). This is to ensure that the
-contract does not suddenly behave differently with a new compiler version. The keyword ``pragma`` is called that way because, in general,
-pragmas are instructions for the compiler about how to treat the
+contract is not compilable with a new (breaking) compiler version, where it could behave differently.
+So-called pragmas are common instrutions for compilers about how to treat the
source code (e.g. `pragma once <https://en.wikipedia.org/wiki/Pragma_once>`_).
A contract in the sense of Solidity is a collection of code (its *functions*) and
data (its *state*) that resides at a specific address on the Ethereum
blockchain. The line ``uint storedData;`` declares a state variable called ``storedData`` of
-type ``uint`` (unsigned integer of 256 bits). You can think of it as a single slot
+type ``uint`` (*u*nsigned *int*eger of *256* bits). You can think of it as a single slot
in a database that can be queried and altered by calling functions of the
code that manages the database. In the case of Ethereum, this is always the owning
contract. And in this case, the functions ``set`` and ``get`` can be used to modify
@@ -49,8 +49,8 @@ or retrieve the value of the variable.
To access a state variable, you do not need the prefix ``this.`` as is common in
other languages.
-This contract does not do much yet (due to the infrastructure
-built by Ethereum) apart from allowing anyone to store a single number that is accessible by
+This contract does not do much yet apart from (due to the infrastructure
+built by Ethereum) allowing anyone to store a single number that is accessible by
anyone in the world without a (feasible) way to prevent you from publishing
this number. Of course, anyone could just call ``set`` again with a different value
and overwrite your number, but the number will still be stored in the history
@@ -62,7 +62,7 @@ so that only you can alter the number.
the ASCII character set. It is possible to store UTF-8 encoded data in string variables.
.. warning::
- Be careful with using Unicode text as similarly looking (or even identical) characters can
+ Be careful with using Unicode text, as similar looking (or even identical) characters can
have different code points and as such will be encoded as a different byte array.
.. index:: ! subcurrency
@@ -72,39 +72,40 @@ 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 trivial
+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 any need for
-registering with 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.4.21;
+ pragma solidity >0.4.24;
contract Coin {
// The keyword "public" makes those variables
- // readable from outside.
+ // easily readable from outside.
address public minter;
mapping (address => uint) public balances;
- // Events allow light clients to react on
+ // Events allow light clients to react to
// changes efficiently.
event Sent(address from, address to, uint amount);
// This is the constructor whose code is
// run only when the contract is created.
- function Coin() public {
+ constructor() public {
minter = msg.sender;
}
function mint(address receiver, uint amount) public {
- if (msg.sender != minter) return;
+ require(msg.sender == minter);
+ require(amount < 1e60);
balances[receiver] += amount;
}
function send(address receiver, uint amount) public {
- if (balances[msg.sender] < amount) return;
+ require(amount <= balances[msg.sender], "Insufficient balance.");
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
@@ -116,15 +117,15 @@ 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 keypairs belonging to external
+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
-to the following::
+to the following (ignore ``external`` and ``view`` for now)::
- function minter() returns (address) { return minter; }
+ function minter() external view returns (address) { return minter; }
Of course, adding a function exactly like that will not work
because we would have a
@@ -137,17 +138,17 @@ 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.
Mappings can be seen as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_ which are
-virtually initialized such that every possible key exists and is mapped to a
+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,
-like this one. The :ref:`getter function<getter-functions>` created by the ``public`` keyword
+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
is a bit more complex in this case. It roughly looks like the
following::
- function balances(address _account) public view returns (uint) {
+ function balances(address _account) external view returns (uint) {
return balances[_account];
}
@@ -162,7 +163,9 @@ a so-called "event" which is emitted in the last line of the function
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 ::
+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)::
Coin.Sent().watch({}, '', function(error, result) {
if (!error) {
@@ -180,23 +183,34 @@ the user interface.
.. index:: coin
-The special function ``Coin`` is the
-constructor which is run during creation of the contract and
+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 magic global variable that
+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
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. On the other hand, ``send`` can be used by anyone (who already
-has some of these coins) to send coins to anyone else. Note that 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
-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
-a "blockchain explorer" that tracks transactions and balances of your new coin.
+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
+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.
+
+.. 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
+ 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
+ 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.
.. _blockchain-basics:
@@ -260,6 +274,10 @@ blocks that are added on top, the less likely it is. So it might be that your tr
are reverted and even removed from the blockchain, but the longer you wait, the less
likely it will be.
+.. note::
+ Transactions are not guaranteed to happen on the next block or any future specific block, since it is up to the miners to include transactions and not the submitter of the transaction. This applies to function calls and contract creation transactions alike.
+
+ If you want to schedule future calls of your contract, you can use the `alarm clock <http://www.ethereum-alarm-clock.com/>`_ service.
.. _the-ethereum-virtual-machine:
@@ -352,19 +370,21 @@ If the gas is used up at any point (i.e. it is negative),
an out-of-gas exception is triggered, which reverts all modifications
made to the state in the current call frame.
+Any unused gas is refunded at the end of the transaction.
+
.. index:: ! storage, ! memory, ! stack
Storage, Memory and the Stack
=============================
-Each account has a persistent memory area which is called **storage**.
+The Ethereum Virtual Machine has three areas where it can store data.
+
+Each account has a data area called **storage**, which is persistent between function calls.
Storage is a key-value store that maps 256-bit words to 256-bit words.
-It is not possible to enumerate storage from within a contract
-and it is comparatively costly to read and even more so, to modify
-storage. A contract can neither read nor write to any storage apart
-from its own.
+It is not possible to enumerate storage from within a contract and it is comparatively costly to read, and even more to modify storage.
+A contract can neither read nor write to any storage apart from its own.
-The second memory area is called **memory**, of which a contract obtains
+The second data area is called **memory**, of which a contract obtains
a freshly cleared instance for each message call. Memory is linear and can be
addressed at byte level, but reads are limited to a width of 256 bits, while writes
can be either 8 bits or 256 bits wide. Memory is expanded by a word (256-bit), when
@@ -373,7 +393,7 @@ within a word). At the time of expansion, the cost in gas must be paid. Memory i
costly the larger it grows (it scales quadratically).
The EVM is not a register machine but a stack machine, so all
-computations are performed on an area called the **stack**. It has a maximum size of
+computations are performed on an data area called the **stack**. It has a maximum size of
1024 elements and contains words of 256 bits. Access to the stack is
limited to the top end in the following way:
It is possible to copy one of
@@ -412,7 +432,7 @@ a top-level message call which in turn can create further message calls.
A contract can decide how much of its remaining **gas** should be sent
with the inner message call and how much it wants to retain.
If an out-of-gas exception happens in the inner call (or any
-other exception), this will be signalled by an error value put onto the stack.
+other exception), this will be signaled by an error value put onto the stack.
In this case, only the gas sent together with the call is used up.
In Solidity, the calling contract causes a manual exception by default in
such situations, so that exceptions "bubble up" the call stack.
@@ -470,21 +490,17 @@ these **create calls** and normal message calls is that the payload data is
executed and the result stored as code and the caller / creator
receives the address of the new contract on the stack.
-.. index:: selfdestruct
+.. index:: selfdestruct, self-destruct, deactivate
-Self-destruct
-=============
+Deactivate and Self-destruct
+============================
-The only possibility that code is removed from the blockchain is
-when a contract at that address performs the ``selfdestruct`` operation.
-The remaining Ether stored at that address is sent to a designated
-target and then the storage and code is removed from the state.
+The only way to remove code from the blockchain is when a contract at that address performs the ``selfdestruct`` operation. The remaining Ether stored at that address is sent to a designated target and then the storage and code is removed from the state. Removing the contract in theory sounds like a good idea, but it is potentially dangerous, as if someone sends Ether to removed contracts, the Ether is forever lost.
-.. warning:: Even if a contract's code does not contain a call to ``selfdestruct``,
- it can still perform that operation using ``delegatecall`` or ``callcode``.
+.. note::
+ Even if a contract's code does not contain a call to ``selfdestruct``, it can still perform that operation using ``delegatecall`` or ``callcode``.
-.. note:: The pruning of old contracts may or may not be implemented by Ethereum
- clients. Additionally, archive nodes could choose to keep the contract storage
- and code indefinitely.
+If you want to deactivate your contracts, you should instead **disable** them by changing some internal state which causes all functions to revert. This makes it impossible to use the contract, as it returns Ether immediately.
-.. note:: Currently **external accounts** cannot be removed from the state.
+.. warning::
+ Even if a contract is removed by "selfdestruct", it is still part of the history of the blockchain and probably retained by most Ethereum nodes. So using "selfdestruct" is not the same as deleting data from a hard disk.