Header Ads

Blockchain Technology: Solidity Tutorials -Part-II.

Subcurrency Example

contract Coin {
    address minter;
    mapping (address => uint) balances;
    function Coin() {
        minter = msg.sender;
    }
    function mint(address owner, uint amount) {
        if (msg.sender != minter) return;
        balances[owner] += amount;
    }
    function send(address receiver, uint amount) {
        if (balances[msg.sender] < amount) return;
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
    }
    function queryBalance(address addr) constant returns (uint balance) {
        return balances[addr];
    }
}
This contract introduces some new concepts. One of them is the address type, which is a 160 bit value that does not allow any arithmetic operations. Furthermore, the state variable balance is of a complex datatype that maps addresses to unsigned integers. Mappings can be seen as hashtables which are virtually initialized such that every possible key exists and is mapped to a value whose byte-representation is all zeros. The special function Coin is the constructor which is run during creation of the contract and cannot be called afterwards. It permanently stores the address of the person creating the contract: Together with tx and blockmsg is a magic global variable that contains some properties which allow access to the world outside of the contract. The function queryBalance is declared constant and thus is not allowed to modify the state of the contract (note that this is not yet enforced, though). In Solidity, return "parameters" are named and essentially create a local variable. So to return the balance, we could also just use balance = balances[addr]; without any return statement.

Comments

Single-line comments (//) and multi-line comments (/*...*/) are possible, while triple-slash comments (///) right in front of function declarations introduce NatSpec comments (which are not covered here).

Types

The currently implemented (elementary) types are booleans (bool), integer and fixed-length string/byte array (bytes0 to bytes32) types. The integer types are signed and unsigned integers of various bit widths (int8/uint8 to int256/uint256 in steps of 8 bits, where uint/int are aliases for uint256/int256) and addresses (of 160 bits).
Comparisons (<=!===, etc.) always yield booleans which can be combined using &&|| and !. Note that the usual short-circuiting rules apply for && and ||, which means that for expressions of the form (0 < 1 || fun()), the function is actually never called.
If an operator is applied to different types, the compiler tries to implicitly convert one of the operands to the type of the other (the same is true for assignments). In general, an implicit conversion is possible if it makes sense semantically and no information is lost: uint8 is convertible to uint16 and int120 to int256, but int8 is not convertible to uint256. Furthermore, unsigned integers can be converted to bytes of the same or larger size, but not vice-versa. Any type that can be converted to uint160 can also be converted to address.
If the compiler does not allow implicit conversion but you know what you are doing, an explicit type conversion is sometimes possible:
int8 y = -3;
uint x = uint(y);
At the end of this code snippet, x will have the value 0xfffff..fd (64 hex characters), which is -3 in two's complement representation of 256 bits.
For convenience, it is not always necessary to explicitly specify the type of a variable, the compiler automatically infers it from the type of the first expression that is assigned to the variable:
uint20 x = 0x123;
var y = x;
Here, the type of y will be uint20. Using var is not possible for function parameters or return parameters. State variables of integer and bytesXX types can be declared as constant.
uint constant x = 32;
bytes3 constant text = "abc";

Integer Literals

The type of integer literals is not determined as long as integer literals are combined with themselves. This is probably best explained with examples:
var x = 1 - 2;
The value of 1 - 2 is -1, which is assigned to x and thus x receives the type int8 -- the smallest type that contains -1. The following code snippet behaves differently, though:
var one = 1;
var two = 2;
var x = one - two;
Here, one and two both have type uint8 which is also propagated to x. The subtraction inside the type uint8 causes wrapping and thus the value of x will be 255.
It is even possible to temporarily exceed the maximum of 256 bits as long as only integer literals are used for the computation:
var x = (0xffffffffffffffffffff * 0xffffffffffffffffffff) * 0;
Here, x will have the value 0 and thus the type uint8.

Ether and Time Units

A literal number can take a suffix of weifinneyszabo or ether to convert between the subdenominations of ether, where Ether currency numbers without a postfix are assumed to be "wei", e.g. 2 ether == 2000 finney evaluates to true.
Furthermore, suffixes of secondsminuteshoursdaysweeks and years can be used to convert between units of time where seconds are the base unit and units are converted naively (i.e. a year is always exactly 365 days, etc.).

Control Structures

Most of the control structures from C/JavaScript are available in Solidity except for switch (not planned) and goto (note that it's called Solidity). So there is: ifelsewhileforbreakcontinuereturn. Note that there is no type conversion from non-boolean to boolean types as there is in C and JavaScript, so if (1) { ... } is not valid Solidity.

Function Calls

Functions of the current contract can be called directly, also recursively, as seen in this nonsensical example:
contract c {
  function g(uint a) returns (uint ret) { return f(); }
  function f() returns (uint ret) { return g(7) + f(); }
}
The expression this.g(8); is also a valid function call, but this time, the function will be called via a message call and not directly via jumps. When calling functions of other contracts, the amount of Wei sent with the call and the gas can be specified:
contract InfoFeed {
  function info() returns (uint ret) { return 42; }
}
contract Consumer {
  InfoFeed feed;
  function setFeed(address addr) { feed = InfoFeed(addr); }
  function callFeed() { feed.info.value(10).gas(800)(); }
}
Note that the expression InfoFeed(addr) performs an explicit type conversion stating that "we know that the type of the contract at the given address is InfoFeed" and this does not execute a constructor. Be careful in that feed.info.value(10).gas(800) only (locally) set the value and amount of gas sent with the function call and only the parentheses at the end perform the actual call.
Function call arguments can also be given by name, in any order:
contract c {
function f(uint key, uint value) { ... }
function g() {
  f({value: 2, key: 3});
}
}
The names for function parameters and return parameters are optional.
contract test {
  function func(uint k, uint) returns(uint){
    return k;
  }
}
Powered by Blogger.