Solidity官方教程学习(一)

Learn Solidity tutorial

Posted by AlbertWu on January 9, 2018

智能合约介绍-原文

简单的智能合约

首先从最基本的例子开始说起,不用担心是否理解每一句代码,之后会对此提供更多细节。

pragma solidity ^0.4.0;

contract SimpleStorage {
    uint storedData;

    function set(uint x) {
        storedData = x;
    }

    function get() constant returns (uint) {
        return storedData;
    }
}

第一行标注了Solidity的版本0.4.0,便于开源社区对代码的重用以及为了确保合约不会在新的编译环境中发生异常。注意至撰文日最新版为0.4.19pragma告知编译器如何编译此份源代码 (e.g. pragma once)。

合约存在于以太坊(Ethereum)区块链中的一个特定地址。uint storeData申明了一个状态变量storedData,其类型为uint(unsigned integer of 256 bits)。 可以理解为该变量是存在数据库一个特定位置的值,并且可以被函数query或者alter。在此例子中setget两个函数可以修改以及获取storedData的值。

要注意的是,为了获取状态变量storedData无需使用前缀this.

接下来我们将会讲到如何限制用户权限,确保不是所有人都可以set存储值。

Subcurrency Example

以下合约是加密货币最简单的实施方案。除了合约创建人其他人均无权限凭空制造货币。并且,任何人彼此间可任意转账,无需用户名密码登录,仅需要拥有以太公钥密钥对 (Ethereum keypair)。

pragma solidity ^0.4.0;

contract Coin {
    // The keyword "public" makes those variables
    // readable from outside.
    address public minter;
    mapping (address => uint) public balances;

    // Events allow light clients to react on
    // 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() {
        minter = msg.sender;
    }

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

    function send(address receiver, uint amount) {
        if (balances[msg.sender] < amount) return;
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        Sent(msg.sender, receiver, amount);
    }
}

address public minter申明了一个类型为address的公开状态变量。address类型是一160-bit的值,拒绝进行任何算术运算。其用于存储合约地址或者keypairs。public使得该值可被其他合约读取,就相当于自动生成了以下函数:

function minter() returns (address) { return minter; }

mapping (address => uint) public balance同样创建了一个公开状态变量,其实现了address到uint的映射。mapping就是一个哈希表,将键值绑定。如以下函数则实现了对于accound的balance的返回:

function balances(address _account) public view returns (uint) {
    return balances[_account];
}

event Sent(address from, address to, uint amount)申明了一个event,在函数send中被调用(fired)。在客户端可以监听该事件在区块链中被调用(fired)并且消耗较低花费。当该事件被调用时,监听器同样会收到三个参数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));
    }
})

在以上代码中,Coin是一个构造函数,要求与合约名相同,仅当合约Coin建立时触发,并且永久保存了创建该合约的用户地址。同时msg也是一个同时创建的全局变量,如msg.sender记录了此时调用该函数的用户地址。

因此在本例中,仅minter可以调用mint函数,而所有人都可以调用send函数,只要他有足够货币。

区块链基础

交易

区块链是全局共享的交易数据库,也就是说网络中的所有人都可以读取数据库中的所有交易信息。同时交易的达成要么是完全达成,要么就是完全不达成,不存在A给B转账,A转出了而B没收到的情况。同时每笔交易都要由转账人A用密钥签名,以确保每一笔交易都被确认。

区块

这里需要解决的问题是双重支付攻击:A只有100ETH,但是在短时间内向网络报告其向B和C均转账100ETH。显然这是不可行的。现解决该问题的办法是一旦第一笔交易被放入一个新的区块,该区块会被网络中所有节点认可,后来者则被拒绝。问题是如果两笔交易间隔时间很小怎么办?现今以太坊加入一个新的区块平均时间间隔为17秒。

以太坊虚拟机(The Ethereum Virtual Machine)

概览

EVM是以太坊中智能合约的运行环境且与网络、文件系统等完全隔绝,并且各个智能合约间无法交流。

账户

To be continued…


Creative Commons License
This work is licensed under a CC A-S 4.0 International License.