#子货币(Subcurrency)例子
下面的合约实现了一个最简单的加密货币。这里,币确实可以无中生有地产生,但是只有创建合约的人才能做到(实现一个不同的发行计划也不难)。而且,任何人都可以给其他人转币,不需要注册用户名和密码 —— 所需要的只是以太坊密钥对。
pragma solidity ^0.4.21;
contract Coin {
// 关键字“public”让这些变量可以从外部读取
address public minter;
mapping (address => uint) public balances;
// 轻客户端可以通过事件针对变化作出高效的反应
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 public minter;
这一行声明了一个可以被公开访问的 address
类型的状态变量。 address
类型是一个160位的值,且不允许任何算数操作。这种类型适合存储合约地址或外部人员的密钥对。关键字 public
自动生成一个函数,允许你在这个合约之外访问这个状态变量的当前值。如果没有这个关键字,其他的合约没有办法访问这个变量。由编译器生成的函数的代码大致如下所示:
function minter() returns (address) { return minter; }
当然,加一个和上面完全一样的函数是行不通的,因为我们会有同名的一个函数和一个变量,这里,主要是希望你能明白——编译器已经帮你实现了。
下一行, mapping (address => uint) public balances;
也创建一个公共状态变量,但它是一个更复杂的数据类型。 该类型将address
映射为无符号整数。 Mappings
可以看作是一个哈希表它会执行虚拟初始化,以使所有可能存在的键都映射到一个字节表示为全0的值。 但是,这种类比并不太恰当,因为它既不能获得映射的所有键的列表,也不能获得所有值的列表。 因此,要么记住你添加到mapping中的数据(使用列表或更高级的数据类型会更好),要么在不需要键列表或值列表的上下文中使用它,就如本例。 而由public
关键字创建的getter函数 getter function 则是更复杂一些的情况, 它大致如下所示:
function balances(address _account) public view returns (uint) {
return balances[_account];
}
正如你所看到的,你可以通过该函数轻松地查询到账户的余额。
event Sent(address from, address to, uint amount);
这行声明了一个所谓的**“事件(event)”**,它会在 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
始终是当前(外部)函数调用的来源地址。
最后,真正被用户或其他合约所调用的,以完成本合约功能的方法是 mint
和 send
。 如果 mint
被合约创建者外的其他人调用则什么也不会发生。 另一方面, send
函数可被任何人用于向他人发送币 (当然,前提是发送者拥有这些币)。记住,如果你使用合约发送币给一个地址,当你在区块链浏览器上查看该地址时是看不到任何相关信息的。因为,**实际上你发送币和更改余额的信息仅仅存储在特定合约的数据存储器中。**通过使用事件,你可以非常简单地为你的新币创建一个“区块链浏览器”来追踪交易和余额。
上一篇:智能合约概述——存储
下一篇:智能合约概述——区块链基础