一篇文章讲明白Facebook币Libra学习

简介: 一篇文章讲明白Facebook币Libra学习

在这个简短的概述中,我们描述了我们在eToro标记化资产背后实施技术的初步经验,即MoveIR语言中的(eToken),用于在Libra网络上进行部署。

Libra协议是一个确定性状态机,它将数据存储在版本化数据库中。使用新颖的领域特定语言:Move。Move允许可编程事务和模块重用代码和状态 - 类似于我们定义为智能合约。

目前,Libra不允许发布模块,这就是为什么eToken的源代码应该作为测试运行的原因。可以在此处找到此Move IR eToken实现的完整源代码。

此测试已在提交哈希中使用Libra版本执行#004d472。可以在此处找到存储库。

Move中间表示语言

随着Libra的发布,定义了一种名为Move的新的特定于域的语言。直到现在,Libra团队尚未提供更高级别的实施。随着该协议的最近宣布,一个名为'Move IR'的lanaguge的一个不太符合人体工程学的中间表示被释放

Move内化了内存所有权和借用的概念,与Rust的运作方式非常相似。然而,Move语言的新颖性是定义“资源”的方式。

“资源”是一种利用所有权模型的结构数据类型,但永远不能仅复制Move和借用。这是Move语言的核心功能,因为它保证没有定义的资源意外重复,从而消除了双重支出或重新发生攻击的可能性。

因此,“资源”的概念与数字资产概念很??好地对应是明智的

eToken实施

modules:

module Capability {

// Capability is responsible for declaring an account's permissions.

// We define the notion of an owner, minter and blacklisted.

// Only the owner can assign blacklisted and minter capabilities.

// The owner is defined by hardcoding its account before publishing the module.

// -

// Declare owner as a resource. It's only meant to be published once

resource Owner { }

// Declare a resource that declares an address's capabilities.

// Every address using EToken will need to publish a resource themselves.

// However, only the owner can change its content.

resource T {

minter: bool,

blacklisted: bool,

}

// Every account should execute this once before using Capability and EToken module.

// If the sender is the hardcoded owner, then owner capability is published.

// Reverts if already published

public publish() {

let sender: address;

sender = get_txn_sender();

// Publish owner capability if sender is the privileged account

// Uncomment the following line in production and use a real owner account: if (move(sender) == 0x0) {

if (true) {

// Always branch to here when testing, otherwise the test can't complete as the sender address is randomly chosen.

Self.grant_owner_capability();

}

// Publish a new capability with no permissions.

move_to_sender(T{ minter: false, blacklisted: false });

return;

}

// Internal function that grants owner capability

grant_owner_capability() {

move_to_sender(Owner {});

return;

}

// Grants minter capability to receiver, but can only succeed if sender owns the owner capability.

public grant_minter_capability(receiver: address, owner_capability: R#Self.Owner) {

let capability_ref: mut R#Self.T;

release(move(owner_capability));

// Pull a mutable reference to the receiver's capability, and change its permission.

capability_ref = borrow_global(move(receiver));

(mut move(capability_ref).minter) = true;

return;

}

// Grants blacklist capability to receiver, but can only succeed if sender owns the owner capability.

public grant_blacklisted_capability(receiver: address, owner_capability: R#Self.Owner) {

let capability_ref: mut R#Self.T;

release(move(owner_capability));

// Pull a mutable reference to the receiver's capability, and change its permission.

capability_ref = borrow_global(move(receiver));

(mut move(capability_ref).blacklisted) = true;

return;

}

// This returns an immutable reference to the owner capability if it exists.

// Is used by the owner to show ownership to privileged functions.

// Reverts if owner capability does not exist.

public borrow_owner_capability(): R#Self.Owner {

let sender: address;

let owner_capability_ref: mut R#Self.Owner;

let owner_capability_immut_ref: R#Self.Owner;

sender = get_txn_sender();

owner_capability_ref = borrow_global(move(sender));

owner_capability_immut_ref = freeze(move(owner_capability_ref));

return move(owner_capability_immut_ref);

}

// This returns an immutable reference to the general capability if it exists.

// Should be used by every account to prove capabilities.

// Reverts if capability does not exist.

public borrow_capability(): R#Self.T {

let sender: address;

let capability_ref: mut R#Self.T;

let capability_immut_ref: R#Self.T;

sender = get_txn_sender();

capability_ref = borrow_global(move(sender));

capability_immut_ref = freeze(move(capability_ref));

return move(capability_immut_ref);

}

// Return whether the capability allows minting.

public is_minter(capability: R#Self.T): bool {

let is_minter: bool;

is_minter = (move(capability).minter);

return move(is_minter);

}

// Return true the capability is not blacklisted.

public is_not_blacklisted(capability: R#Self.T): bool {

let is_blacklisted: bool;

is_blacklisted = (move(capability).blacklisted);

return !move(is_blacklisted);

}

// Reverts if capability does not allow minting

public require_minter(capability: R#Self.T) {

let is_minter: bool;

is_minter = Self.is_minter(move(capability));

assert(move(is_minter), 0);

return;

}

// Reverts if capability is blacklisted

public require_not_blacklisted(capability: R#Self.T) {

let is_not_blacklisted: bool;

is_not_blacklisted = Self.is_not_blacklisted(move(capability));

assert(move(is_not_blacklisted), 0);

return;

}

}

module EToken {

// This module is responsible for an actual eToken.

// For it to be useful a capability has to be published by using the Capability module above.

// -

import Transaction.Capability;

// Declare the eToken resource, storing an account's total balance.

resource T {

value: u64,

}

// Publishes an initial zero eToken to the sender.

// Should be called once before using this module.

public publish() {

move_to_sender(T{ value: 0 });

return;

}

// Mint new eTokens.

// Reverts if capability does not allow it.

public mint(value: u64, capability: R#Capability.T): R#Self.T {

Capability.require_minter(move(capability));

return T{value: move(value)};

}

// Returns an account's eToken balance.

// Reverts if an initial eToken hasn't been published.

public balance(): u64 {

let sender: address;

let token_ref: mut R#Self.T;

let token_value: u64;

sender = get_txn_sender();

token_ref = borrow_global(move(sender));

token_value = (move(token_ref).value);

return move(token_value);

}

// Deposit owned tokens to an payee's address, and destroy the tokens to deposit,

// Reverts if user is blacklisted.

public deposit(payee: address, to_deposit: R#Self.T, capability: R#Capability.T) {

let payee_token_ref: mut R#Self.T;

let payee_token_value: u64;

let to_deposit_value: u64;

Capability.require_not_blacklisted(move(capability));

payee_token_ref = borrow_global(move(payee));

payee_token_value = (copy(payee_token_ref).value);

// Unpack and destroy to_deposit tokens

T{ value: to_deposit_value } = move(to_deposit);

// Increase the payees balance with the destroyed token amount

(mut move(payee_token_ref).value) = move(payee_token_value) + move(to_deposit_value);

return;

}

// Withdraw an amount of tokens of the sender and return it.

// This works by splitting the token published and returning the specified amount as tokens.

public withdraw(amount: u64, capability: R#Capability.T): R#Self.T {

let sender: address;

let sender_token_ref: mut R#Self.T;

let value: u64;

Capability.require_not_blacklisted(move(capability));

sender = get_txn_sender();

sender_token_ref = borrow_global(move(sender));

value = (copy(sender_token_ref).value);

// Make sure that sender has enough tokens

assert(copy(value) >= copy(amount), 1);

// Split the senders token and return the amount specified

(mut move(sender_token_ref).value) = move(value) - copy(amount);

return T{ value: move(amount) };

}

}

script:

// Performs simple testing to crudely verify the published modules above.

import Transaction.Capability;

import Transaction.EToken;

main() {

let sender: address;

let owner_capability: R#Capability.Owner;

let capability: R#Capability.T;

let minted_tokens: //代码效果参考:http://www.zidongmutanji.com/zsjx/302939.html

R#EToken.T;

let balance: u64;

sender = get_txn_sender();

// Publish initial capability

Capability.publish();

// Borrow owner_capability for minter delegation

owner_capability = Capability.borrow_owner_capability();

// Delegate itself as a minter

Capability.grant_minter_capability(copy(sender), move(owner_capability));

// Borrow general capability for proof of minting capability

capability = Capability.borrow_capability();

// Publish an eToken account

EToken.publish();

// Mint 100 eTokens and prove minter capability

minted_tokens = EToken.mint(100, copy(capability));

// Deposit the freshly minted tokens to itself

EToken.deposit(move(sender), move(minted_tokens), move(capability));

// Test that the balance corresponds with the intended behaviour

balance = EToken.balance();

assert(move(balance) == 100, 3);

return;

}

View Code

eToken目前部署在以太坊区块链上,包括为生产中使用标记化而实现的几个重要功能。

最重要的功能如下所列。粗体功能也已在Move IR中实现。

角色(破坏者,黑名单)

造币

燃烧

暂停

可升级

我们将一个角色定义为Move实现中的一个功能,命名更改是为了遵守Libra自己的硬币实现的标准。

能力

为了能够授予minter和blacklist权限,我们必须指定模块的所有者。作为模块的所有者,用户可以将帐户添加为小工具和黑名单。

我们首先定义所有者资源,该资源仅用于发布一次。它在Capability模块中声明。

resource Owner { }

然后,我们通过将已发布资源Move到指定所有者来授予所有权。在这里,我们在尝试使用该语言时遇到了一些问题,以保证所有者功能只发布一次。

在初始模块发布期间,Move IR定义似乎不支持仅定义为可执行一次的函数,也称为构造函数。

当然,这将是授予“所有者”能力的理想场所。

此外,Move IR不直接支持全局变量,这可能是将函数定义为已执行的不安全方式。

为了规避这些限制,我们使用硬编码的所有者地址创建了模块,从而创建了单例资源。因此,只有在所有者作为发件人发布功能资源时才会执行所有权授予:

public publish() {

let sender: address;

sender = get_txn_sender();

// Publish owner capability if sender is the privileged account

// Replace 0x0 address with a real owner account address

if (move(sender) == 0x0) {

Self.grant_owner_capability();

}

...

模块不能代表发件人之外的其他帐户发布资源。从而,让帐户完全控制与他们相关的内容。publish()因此,该功能必须由希望获得有效能力的所有帐户执行,这对于进一步的令牌使用是强制性的。

Neverthelss,强制执行硬编码的所有者地址并不是一个优雅的解决方案。我们向Libra团队提出了这个问题,团队成员建议实施合成糖替换硬编码地址fx。Self.publisher_address。

实际所有权授予是通过调用内部函数来完成的,该函数grant_owner_capability()创建Owner资源并将其发布到发件人帐户。这是通过执行以下表达式完成的:

move_to_sender(Owner {});

通过将所述功能实现为内部,VM保证它只能由模块内部执行。通过仅在发件人是指定的所有者地址时调用该函数,我们确保它只发布一次。

该publish()还发布没有权限调用它,因为需要进一步令牌使用的所有帐户的能力。

它只会在已经存在的情况下恢复。

通过将所有权定义为资源,我们可以确保它不能被复制。它还为我们提供了一种令人愉快的类型安全的方式来保护特权功能,例如授予其他人的铸造能力。这是通过简单地要求借用Owner资源作为特权函数的参数来实现的。帐户只能通过调用borrow_owner_capability()函数来获取借用的引用,如果函数存在于发送方地址,则返回借用的引用。以下摘录举例说明了所有者特权函数:

// Grants minter capability to receiver, but can only succeed if sender owns the owner capability.

public grant_minter_capability(receiver: address, owner_capability: R#Self.Owner) {

let capability_ref: mut R#Self.T;

release(move(owner_capability));

...

借用的所有者功能仅用于类型安全性,因此立即释放给发送方:如果功能成功执行,则会改变位于该receiver地址的功能资源。

...

// Pull a mutable reference to the receiver's capability, and change its permission.

capability_ref = borrow_global(move(receiver));

(mut move(capability_ref).minter) = true;

...

代币

通过使用功能模块定义eToken的角色和权限,我们现在可以继续实际的令牌实现。

我们首先声明令牌资源,该资源包含所述令牌的数量。

resource T {

value: u64,

}

与其他智能合约语言相比,Move的优势显而易见。如果我们要存放一些令牌,我们必须控制令牌的内存所有权。我们只能通过拆分现有的自有令牌(也称为撤销)或铸造新鲜令牌来获得此所有权。

这种所有权属性保证了相同的令牌不能存在于其他地方,从而消除了因错误复制而导致的错误,从而导致双重花费和其他错误行为。

此外,内存所有权模型还要求必须明确销毁拥有的令牌或将其Move到另一个所有者。这可以保证令牌不会被意外锁定在模块内,永远不会被再次检索。

通过利用这种类型安全的属性,我们可以定义存放自有令牌的功能。

public deposit(payee: address, to_deposit: R#Self.T, capability: R#Capability.T) {

...

Capability.require_not_blacklisted(move(capability));

payee_token_ref = borrow_global(move(payee));

payee_token_value = (copy(payee_token_ref).value);

// Unpack and destory to_deposit tokens

T{ value: to_deposit_value } = move(to_deposit);

// Increase the payees balance with the destroyed token amount

(mut move(payee_token_ref).value) = move(payee_token_value) + move(to_deposit_value);

...

我们首先确保用户未被列入黑名单。接下来,我们通过解压缩其内部数量变量来销毁所拥有的令牌。最后,我们通过解压缩的金额增加收款人的代币。

与存款相反,当从发件人的帐户中提取令牌时,我们将令牌分成两部分,并将新令牌的所有权归还给来电者。

通过首先减少发件人令牌数量,然后返回新的令牌资源来完成拆分。

*(mut move(sender_token_ref).value) = move(value) - copy(amount);

return T{ value: move(amount) };

结论

总而言之,Libra和Move IR是智能合约开发中值得欢迎的一步。拥有强大的资产保证可以帮助开发人员减少容易出错的代码并加快Move速度。

尽管如此,Move IR仍然处于早期阶段,并且在当前迭代中不是用户友好的。由于某种原因,它被称为“中间代表”:-)

我们将密切关注这一发展,并对新的发展感到兴奋。

尝试并运行测试

如果您有兴趣了解Libra网络和Move IR,我们建议您运行测试以熟悉上述概念。要运行原始eToken实现测试,您应该执行以下步骤:

克隆Libra存储库(最好是在引言中声明的提交哈希)

跟随LibraREADME如何编译和安装它。

克隆此存储库

将位于src/eToken.mvir此存储库中的eToken Move IR源代码复制到位于的Libra存储库中的测试文件夹language/functional_tests/tests/testsuite/modules/

在Libra存储库中的某处执行以下命令: cargo test -p functional_tests eToken

相关文章
|
6月前
|
存储 Rust 安全
一篇文章讲明白Facebook币Libra学习
一篇文章讲明白Facebook币Libra学习
48 0
|
机器学习/深度学习 人工智能 JavaScript
自动写代码指日可待!Facebook迁移学习新突破,代码补全准确率超50%!(二)
程序员的工作就是取代重复、算法可替代的工作,而他们自己也在研究如何取代自己。Facebook新发表的代码补全模型准确率超50%,动动手指就能写几百行代码!
184 0
自动写代码指日可待!Facebook迁移学习新突破,代码补全准确率超50%!(二)
|
机器学习/深度学习 自然语言处理 IDE
自动写代码指日可待!Facebook迁移学习新突破,代码补全准确率超50%!(一)
程序员的工作就是取代重复、算法可替代的工作,而他们自己也在研究如何取代自己。Facebook新发表的代码补全模型准确率超50%,动动手指就能写几百行代码!
176 0
自动写代码指日可待!Facebook迁移学习新突破,代码补全准确率超50%!(一)
|
机器学习/深度学习 人工智能 安全
如何高效验证深度神经网络的学习行为?看看 Facebook 是怎么做的
能够比当前 state-of-the-art 程序更快识别应用安全水平的最新技术。
479 0
|
存储 区块链
Facebook Libra 性能初探
译自:官方文档翻译 《Libra 技术白皮书》。 本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行许可。 Libra 中文网同步翻译 http://www.libra-cn.top/document/info/?id=18 Libra 协议的使命在于至此全球的金融基础设施。
1616 0
|
机器学习/深度学习 自然语言处理
Facebook最新对抗学习研究:无需平行语料库完成无监督机器翻译
Facebook试图将机器翻译的成功扩展到低资源语言对,研究了在没有任何平行数据的情况下,实现无监督的机器翻译。他们提出的模型有效地学习了在不使用任何标记数据的情况下进行翻译。 论文下载链接:https://arxiv.org/pdf/1711.00043.pdf 相信大家都知道,最近在机器翻译领域取得了令人印象深刻的成果,而这主要归功于最近在深度学习方面所取得巨大进步,以及大规模平行语料库(large-scale parallel corpora)的可用性。
1417 0
|
机器学习/深度学习 人工智能 机器人
|
机器学习/深度学习 算法 决策智能
【重磅开源】Facebook开源 Nevergrad:一种用于无梯度优化的开源工具
【重磅开源】Facebook开源 Nevergrad:一种用于无梯度优化的开源工具
207 0
|
缓存 数据可视化 测试技术
开源多年后,Facebook这个调试工具,再登Github热门榜
让许多工程师合作开发大型应用大多会面临一个挑战,通常没有一个人知道每个模块是如何工作的,这种技能会让开发新功能、调查Bug或优化性能变得困难,为了解决这个问题,Facebook创建并开源了Flipper,一个可扩展的跨平台的调试工具,用来调试 iOS 和 Android 应用。近日又双叒登上了Github热榜。
|
前端开发 JavaScript 测试技术
Facebook 开源可扩展文本编辑器 Lexical
Meta(原 Facebook)近日开源可扩展文本编辑器 Lexical,源代码托管在 GitHub 上采用 MIT 许可证。
548 0
Facebook 开源可扩展文本编辑器 Lexical