From 931b93146fa8655fcd282cce7365f87bb0c48bed Mon Sep 17 00:00:00 2001 From: Chris Ward Date: Tue, 23 Apr 2019 16:40:43 +1000 Subject: [PATCH] Update subcurrency example in introductory section Further updates Add line breaks Changes from review Updates from review Changes from review Fix label --- docs/introduction-to-smart-contracts.rst | 126 +++++++++++------------ docs/types/value-types.rst | 1 + docs/units-and-global-variables.rst | 2 + 3 files changed, 65 insertions(+), 64 deletions(-) diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 7d99e94a6..7aa51d070 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -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
`. +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`. + +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 ` type maps addresses to :ref:`unsigned integers `. + Mappings can be seen as `hash tables `_ 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` 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" `, 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 `_ 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` 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 ` 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 ` 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 ======== diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 9c082f9b4..4451ac01f 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -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 -------- diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index befb97dbb..c797187be 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -52,6 +52,8 @@ interpret a function parameter in days, you can in the following way:: } } +.. _special-variables-functions: + Special Variables and Functions ===============================