智能合约开发(2)—— solidity简单程序和代币

solidity是契约导向的实现智能合约的高级语言,受到 C++,Python和JavaScript的影响,旨在针对以太坊虚拟机(EVM)。solidity是静态类型的语言,支持继承,库和复杂的用户定义类型等功能。可以用了创建投票,众筹,拍卖(盲拍),多重签名钱包等等的合约。
2.智能合约
2.1 一个简单的智能合约
2.1.1 storage

pragma solidity ^0.4.0;

contract SimpleStorage{
    uint storedData;

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

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

第一行意义前面有说。
solidity意义上的合约是位于以太坊区块链的特定地址的代码(功能)和数据(状态)的集合。
uint storedData;声明一个类型为uint(无符号整数为256位)的称为storedData的状态变量。函数set和get可以用来修改或检索变量的值。
这个程序除了允许世界上任何人存储一个世界上所有人都可以访问和修改的数字以外并无其他意义,不过后面会涉及到如何来强制进行访问限制。
除了简单存储一个数字外,以太坊的基础结构决定了这个合约还可以做更多的事,这个世界上没有一个可行的方法来阻止你发布这个数字。虽然任何人都可以用一个任意的数字来set again,但这个数字会永久的保存在区块链的历史记录中。

所有标识符(合同名称,函数名称,变量名称)都限制为ASCII字符集。
可以在字符串变量中存储UTF-8编码的数据。
使用Unicode文本时要小心,因为类似的甚至相同的字符可以拥有不同的code points,因此会被编码为不同的字节数据。

2.1.2 代币
下面的合约将实现一个加密货币的最简单形式。可以凭空产生货币,但是这只有创建合约的人才能做到(用其他货币的发行模式也很简单,只是实现细节上的差异)。此外,任何人都可以互相发送货币,无需注册用户名和密码——只需要一个以太坊秘钥对。

pragma solidity ^0.4.0;

contract Coin{
    //"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 pubilc minter;这行代码声明了一个可公开 访问的状态变量,类型为address。address类型为160bits,不允许任何算术运算。public关键字会自动生成一个函数,允许访问状态变量的当前值。没有public关键字的变量讲无法被其他合约访问。该函数如下:

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

当然,添加一个类似这样的函数是行不通的,因为有一个状态变量和该函数重名,并且编译器也会报错的。
下一行mapping (address => uint) public balances;创建了一个public状态变量。这个类型将地址映射为无符号整形。mapping可以被认为是一个哈希表,每一个可能的key对应的value被虚拟的初始化为全0。这个类比不是很严谨,对于一个mapping,无法获取一个包含其所有key或者value的链表。所以我们需要自己记着添加了哪些东西到mapping中。更好的方式是维护一个这样的链表,或者使用其他更高级的数据类型。或者只在不受这个缺陷影响的场景中使用mapping,就像这个例子。在这个例子中由public关键字生成的访问函数将会更加复杂,其代码大致如下:

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

我们可以通过这个函数查询某个特定账号的余额。
这行代码event Sent(address from, address to ,uint amount);声明一个“event”在最后一行的函数“send”中被触发。

客户端(服务端应用同样适用)可以以很低的开销来监听这些由区块链触发的事件。事件触发时,监听着会同时接收到from, to, value这些参数值,可以方便的用于跟踪交易。为了监听这个事件,你可以使用:

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.arg.from) +
    "Receiver: " + Coin.balances.call(result.args.to));
   }
}

注意在客户端中如何调用自动生成的 balance 函数的。

这里有个比较特殊的函数Coin。它是一个构造函数,会在合约创建的时候运行,之后就无法被调用。它会永久得存储合约创建者的地址。msg(以及tx和block)是一个神奇的全局变量,它包含了一些可以被合约代码访问的属于区块链的属性。msg.sender总是存放着当前函数的外部调用者的地址。(这里有个很大的疑惑,不知道这个程序是怎样保证Coin函数只在合约创建时运行的)

最后,真正被用户或者其他合约调用,用来完成本合约功能的函数是mint 和 send。如果合约创建者之外的其他人调用mint,什么都不会发生(写的地址必须是minter)。而send可以被任何人(拥有一定数量代币)调用,发送一些币给其他人。注意当你通过该合约发送一些代币到某个地址,在区块链浏览器中查询该地址将什么也看不到。因为发送代币导致的余额变化只存储在该代币合约的数据存储中。通过事件我们可以很容易创建一个可以追踪你的新币交易和余额的“区块链浏览器”

以上内容是sunniy27翻译solidity官方文档的学习心得

猜你喜欢

转载自blog.csdn.net/weixin_42595515/article/details/81805273