一个公开的区块链需要密码学货币来激励用户参与共识过程,这已经是一个被广泛接受的观点了,正如这张搞笑图片所表达的:
问题是,我们是否可以创造一个不依赖任何特定货币的区块链,让人们可以用任何他们想用的货币进行交易呢?在工作量证明,尤其是只有交易费奖励的环境下,这是相对容易实现的。只需要定下一个区块大小限制,然后让矿工和交易发送者自己就交易价格达到某种均衡即可(交易费用或许可以通过信用卡批量支付)。对于以太坊来说则有些复杂。原因是目前的以太坊1.0版本引入了一个燃料机制(gas),来帮助矿工可以安全地接受交易而无须担心拒绝服务攻击的风险。这个机制是这样工作的:
每一个交易都指定好gas消耗上限,以及每单位gas的价格。
假设这个交易的gas上限是N. 如果交易是有效的,而且只用了不到N的计算量(设用掉的计算量为M),那么它要支付计算量M对应的手续费。如果交易在处理结束之前用光了N单位的计算量,执行被回滚,而且依然要支付计算量N对应的手续费。
这个机制依赖于受协议控制的特定货币ETH(以太币)的存在。我们是否可以不依赖任何特定货币实现这个机制呢?答案是可以的,至少我们可以把它和上文提到的“使用任意密码学算法”的方案相结合。方法如下。首先,我们稍微扩展一下上面的具有密码学算法中立性的方案:与其用一个新概念“验证程序”来决定某个交易是否有效,不如只保留一种账户类型 - 合约账户,此时交易可以简单看作是从零地址发出的一条消息。如果交易执行在50000 gas的额度下异常中止,它就是无效的;否则就是有效的并且被接受。在这个模型中,我们的账户遵循以下规则:
检查交易是否正确。如果不是,退出。如果是,向一个主合约(master contract)支付一些gas费用,主合约之后会支付矿工。
发送实际的消息。
发消息通知主合约。然后主合约会检查还有多少gas剩下,把余额退还给交易发起人,其余的支付给矿工。
第一步可以有一个标准形式,以便清楚地表明所需的gas不到50000。第三步也可以这样构造。第二步中消息的gas消耗上限可以等于交易指定上限减去100000。然后矿工们就可以只接受与标准形式模式匹配的交易(当然新的标准形式可以随着时间慢慢增加),而且他们也能确定没有任何一笔交易可以消耗超过50000单位的计算量。于是,所有东西都通过gas上限来控制,而矿工和交易发起人可以使用他们喜欢的任何货币。
一个冒出来的挑战是:如果为合约使用进行支付呢?目前,合约可以为提供的服务“收费”,代码类似下面的域名注册示例:
def reserve(_name:bytes32): if msg.value > 100 * 10**18: if not self.domains[_name].owner: self.domains[_name].owner = msg.sender
如果有多种货币,就没有一个清晰的机制可以把一条消息和它的支付联系起来。不过有两种常用设计模式可以作为替代。第一种是一种“收据”接口:当你支付货币给他人时,你可以要求货币合约保存付款人和支付数额信息。类似于registrar.reserve("blahblahblah.eth")的代码则会变成:
gavcoin.sendWithReceipt(registrar, 100 * 10**18) registrar.reserve("blahblahblah.eth")
这个货币的合约会有类似这样的代码:
``` def sendWithReceipt(to, value): if self.balances[msg.sender] >= value: self.balances[msg.sender] -= value self.balances[to] = value self.last_sender = msg.sender self.last_recipient = to self.last_value = value
def getLastReceipt(): return([self.last_sender, self.last_recipient, self.value]:arr) ```
注册代码则是这样的:
def reserve(_name:bytes32): r = gavcoin.getLastReceipt(outitems=3) if r[0] == msg.sender and r[1] == self and r[2] >= 100 * 10**18: if not self.domains[_name].owner: self.domains[_name].owner = msg.sender
基本上注册合约会检查货币合约中的最后一笔支付,确保支付对象是自己。为了防止重复使用同一笔支付,在读收据数据时让get_last_receipt方法销毁收据也许是有必要的。
另一个设计模式是让货币合约提供一个允许其它地址从你的账户取款的接口。从调用者的角度来看代码会是这样:首先,批准一笔一定数额的一次性取款,然后调用reserve,然后注册合约尝试取款,如果成功则继续处理:
gavcoin.approveOnce(registrar, 100) registrar.reserve("blahblahblah.eth")
注册合约会变成:
def reserve(_name:bytes32): if gavcoin.sendCoinFrom(msg.sender, 100, self) == SUCCESS: if not self.domains[_name].owner: self.domains[_name].owner = msg.sender
okex以太坊今日行情