Solidity-简单的智能合约及其概念

源码:
pragma solidity ^0.4.0;
contract SimpleStorage {
    uint storedData; // 声明一个类型为uint的状态变量,uint=256位无符号整数
    function set(uint x) public {
        storedData = x;
    }
    function get() public constant returns (uint) {
        return storedData;
    }
}
pragma是一个版本杂注的编译指令,它告知编译器如何处理源代码的指令。这里告知编译器源码使用不低于solidity 0.4.0版本不高于但包含0.5.0版本的编译器编写,第二个条件由符号^指定。它的作用类似于C/C++的pragma。
solidity中合约的含义就是一组代码和数据,代码就是函数,数据就是状态,它们安装在以太坊区块链的一个特定地址上。
这个合约完成的事情是:它允许任何人在其中存储一个数字,同时这个数字可以被世界上任何人访问到,也没有什么办法阻止你发布这个数字。
任何人都可以再次调用set,传入不同的值,覆盖你的数字,但是这个数字仍会被存储在区块链的历史记录中,随后,我们会看到怎样施加访问限制,以确保只有你才能改变这个数字。
Solidity-简单的智能合约及其概念_第1张图片
这里所有的标识符(合约名称,函数名称和变量名称)都只能使用ASCII字符集,UTF-8编码的数据可以用字符串变量的形式存储。
小心使用Unicode文本,虽然有些字符看的很像,甚至一样,但其字符码是不同的,其编码后的字符数组也会不一样。

子货币实例:
pragma solidity ^0.4.21;
contract Coin {
    // 关键字“public”让这些变量可以从外部读取,它声明了一个可被公开访问的address类型的状态变量
    address public minter;
    mapping (address => uint) public balances;//创建一个公共状态变量,该类型将address映射为无符号整数

    // 轻客户端可以通过事件针对变化作出高效的反应,声明一个事件,在send函数最后一行会被发出,监听该事件的listener都将收到
    event Sent(address from, address to, uint amount);
    // 这是构造函数,只有当合约创建时运行
    function Coin() public {
        minter = msg.sender;
    }

    function mint(address receiver, uint amount) public {
        if (msg.sender != minter) return;
        balances[receiver] += amount;
    }
    function send(address receiver, uint amount) public {

        if (balances[msg.sender] < amount) return;
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}


上面实现一个简单的加密货币,币在这里可以无中生有,但只有创建合约的人才能做到,且任何人都可以给他人转币,无需注册名和密码,所需要的只是以太坊密钥对。
address类型是一个160位的值,不允许任何算数操作,这种类型适合存储合约地址或外部人员的密钥对。
关键字public自动生成一个函数,允许在这个合约之外访问这个状态变量的当前值,若没有这个关键字,其他合约无法访问这个变量,由编译器生成的函数代码大致如下:
function minter() returns (address) { return minter; }
这里加上一个和上面完全一样的函数是不行的,因为会有同名的一个函数和一个变量,这里主要希望能明白--编译器已经帮忙实现了。
mappings可看作是一个哈希表,它会执行虚拟初始化,以使得所有可能存在的键都映射到一个字节表示为全零的值。但是,这种类比并不恰当,因为它既不能获得映射的所有键的立碑,也不能获得所有值的列表,因此,要么记住添加到mapping中的数据,要么在不需要键列表或值列表的上下文中使用它,就如本例。而由public关键字创建的getter函数getter function则是更复杂一些的情况,后面解释什么是getter函数,它大概如下所示:
function balances(address _account) public view returns (uint) {
    return balances[_account];
}
使用它可很容易查询到账户余额。

event Sent(address from, address to, uint amount);声明了一个所谓的事件,它在send函数最后一行被发出。用户界面可以监听区块链上正在发送的事件,且不会花费太多成本,一旦它被发出,监听该事件的listener都将收到通知,而所有的事件都包含了from,to和amount三个参数,可方便追踪事务。为了监听这个事件,可使用如下代码:
Coin.Sent().watch({}, '', function(error, result) {
    if (!error) {
        console.log("Coin transfer: " + result.args.amount +
            " coins were sent from " + result.args.from +
            " to " + result.args.to + ".");
        console.log("Balances now:\n" +
            "Sender: " + Coin.balances.call(result.args.from) +
            "Receiver: " + Coin.balances.call(result.args.to));
    }
})
这里注意自动生成的balances函数是如何从用户界面调用的。
特殊函数Coin是在创建合约期间运行的构造函数,不能在事后调用。它永久存储创建合约的人的地址:msg是一个全局变量,还有tx和block,其中包含一些允许访问区块链的属性。msg.sender始终是当前函数或者外部函数调用的来源地址。
Solidity-简单的智能合约及其概念_第2张图片
最后真正被用户和其他合约所调用的,用于完成本合约功能的方法是mint和send。若mint被合约创建者外的其他调用则说明都不会发生。
send函数可被任何人用于向其他人发送代币,前提是发送者拥有这些代币,若使用合约发送代币给一个地址,当在区块链浏览器上查到该地址时时看不到任何相关信息的,因为,实际上发送币和更改余额的信息仅仅存在特定合约的数据存储器中。通过使用事件,可非常简单地为新币创建一个区块链浏览器来追踪交易和余额。

什么是getter函数?
编译器会为所有用public声明的状态变量自动创建getter函数,如下例合约所示,编译器会自动生成一个不带任何参数且返回
一个uint值的名为call的函数,返回的uint值就是状态变量data的值,可以在声明时初始化状态变量的值:
pragma solidity ^0.4.0;
contract C {
    uint public data = 42;
}
contract Caller {
    C c = new C();
    function f() public {
        uint local = c.data();
    }
}
getter函数还有扩展可见性。若该函数是内部访问,它被认为是一个状态变量,不用this.引用。若是外部访问则被认为是一个函数,用this.引用访问。如下所示:
pragma solidity ^0.4.0;
contract C {
    uint public data;
    function x() public {
        data = 3; // internal access
        uint val = this.data(); // external access
    }
}
下面的实例更复杂一些:
pragma solidity ^0.4.0;
contract Complex {
    struct Data {
        uint a;
        bytes3 b;
        mapping (uint => uint) map;
    }
    mapping (uint => mapping(bool => Data[])) public data;
}
它会生成一个如下所示格式的函数:
function data(uint arg1, bool arg2, uint arg3) public returns (uint a, bytes3 b) {
    a = data[arg1][arg2][arg3].a;
    b = data[arg1][arg2][arg3].b;
}
注意的是因为没有一个好的方法来为mapping提供键,所以结构体中的mapping被忽略。
参考 网址

你可能感兴趣的:(区块链)