Facebook币Libra学习

Stella981
• 阅读 684

Move是一种新的编程语言,旨在为Libra Blockchain提供安全可编程的基础。Libra Blockchain中的帐户是任意数量的Move资源和Move模块的容器。提交给Libra Blockchain的每个事务都使用Move中编写的事务脚本来编码其逻辑。事务脚本可以调用模块声明的过程来更新区块链的全局状态。

在本指南的第一部分中,我们将对Move语言的主要功能进行高级介绍:

  1. 移动事务脚本启用可编程事务
  2. 移动模块允许可组合智能合约
  3. 移动有一流的资源

对于好奇的读者,Move技术论文包含有关该语言的更多细节。

在本指南的第二部分中,我们将“深入了解”并向您展示如何在Move中间表示中编写您自己的Move程序。初始testnet版本不支持自定义移动程序,但这些功能可供您在本地试用。

移动的主要特点

移动事务脚本启用可编程事务

  • 每个Libra事务都包含一个Move事务脚本,该脚本对验证器应代表客户端执行的逻辑进行编码(例如,将Libra从Alice的帐户移动到Bob的帐户)。
  • 事务脚本通过调用一个或多个Move模块的过程与Libra Blockchain的全局存储中发布的Move资源进行交互。
  • 事务脚本不存储在全局状态中,并且其他事务脚本无法调用它。这是一次性使用的程序。
  • 我们在编写事务脚本中提供了几个事务脚本示例。

移动模块允许可组合智能合约

移动模块定义了更新Libra Blockchain全局状态的规则。模块在其他区块链系统中与智能合约相同。模块声明可以在用户帐户下发布的资源类型。Libra Blockchain中的每个帐户都是一个容器,可以容纳任意数量的资源和模块。

  • 模块声明两种结构类型(包括资源,这是一种特殊的结构)和过程。
  • Move模块的过程定义了创建,访问和销毁它声明的类型的规则。
  • 模块可重复使用。在一个模块中声明的结构类型可以使用在另一个模块中声明的结构类型,并且在一个模块中声明的过程可以调用在另一个模块中声明的公共过程。模块可以调用其他Move模块中声明的过程。事务脚本可以调用已发布模块的任何公共过程。
  • 最终,Libra用户将能够在自己的帐户下发布模块。

移动有一流的资源

  • Move的关键功能是定义自定义资源类型的能力。资源类型用于编码具有丰富可编程性的安全数字资产。
  • 资源是语言中的普通值。它们可以存储为数据结构,作为参数传递给过程,从过程返回,等等。
  • Move类型系统为资源提供特殊的安全保证。移动资源永远不会被复制,重用或丢弃。资源类型只能由定义类型的模块创建或销毁。这些保证由Move虚拟机通过字节码验证静态实施。Move虚拟机将拒绝运行未通过字节码验证程序的代码。
  • Libra货币实现为名为的资源类型LibraCoin.TLibraCoin.T在该语言中没有特殊的地位; 每个Move资源都享有相同的保护。

移动:在引擎盖下

移动中间表示

本节介绍如何在Move中间表示(IR)中编写事务脚本模块。我们提醒读者,IR是即将推出的Move源语言的早期(且不稳定)前体(有关更多详细信息,请参阅Future Developer Experience)。移动IR是移动字节码上的一个薄语法层,用于测试字节码验证器和虚拟机,它不是特别适合开发人员。它的高级别足以编写人类可读的代码,但低级别足以直接编译为移动字节码。尽管如此,我们对Move语言感到很兴奋,并希望开发人员尽可能地尝试IR,尽管边缘粗糙。

我们将继续介绍重要评论的Move IR的片段。我们鼓励读者通过在本地编译,运行和修改示例来跟随这些示例。README文件libra/language/README.mdlibra/language/compiler/README.md解释如何执行此操作。

编写交易脚本

正如我们在Move Transaction Scripts Enable Programmable Transactions中所述,用户编写事务脚本以请求更新Libra Blockchain的全局存储。几乎所有事务脚本中都会出现两个重要的构建块:资源类型LibraAccount.TLibraCoin.T资源类型。LibraAccount是模块T的名称,是该模块声明的资源的名称。这是Move中常见的命名约定; 模块声明的“main”类型通常是命名的T

When we say that a user "has an account at address 0xff on the Libra Blockchain", what we mean is that the address 0xff holds an instance of the LibraAccount.T resource. Every nonempty address has a LibraAccount.T resource. This resource stores account data, such as the sequence number, authentication key, and balance. Any part of the Libra system that wants to interact with an account must do so by reading data from the LibraAccount.T resource or invoking procedures of the LibraAccount module.

帐户余额是类型的资源LibraCoin.T。正如我们在Move Has First Class Resources中所解释的那样,这是天秤座硬币的类型。与任何其他Move资源一样,此类型是语言中的“一等公民”。类型的资源LibraCoin.T可以存储在程序变量中,在程序之间传递,等等。

我们鼓励感兴趣的读者检查目录下LibraAccountLibraCoin模块中这两个关键资源的Move IR定义libra/language/stdlib/modules/

现在让我们看看程序员如何在事务脚本中与这些模块和资源进行交互。

// Simple peer-peer payment example.

// Use LibraAccount module published on the blockchain at account address
// 0x0...0 (with 64 zeroes). 0x0 is shorthand that the IR pads out to
// 256 bits (64 digits) by adding leading zeroes.
import 0x0.LibraAccount; import 0x0.LibraCoin; main(payee: address, amount: u64) { // The bytecode (and consequently, the IR) has typed locals. The scope of // each local is the entire procedure. All local variable declarations must // be at the beginning of the procedure. Declaration and initialization of // variables are separate operations, but the bytecode verifier will prevent // any attempt to use an uninitialized variable. let coin: R#LibraCoin.T; // The R# part of the type above is one of two *kind annotation* R# and V# // (shorthand for "Resource" and "unrestricted Value"). These annotations // must match the kind of the type declaration (e.g., does the LibraCoin // module declare `resource T` or `struct T`?). // Acquire a LibraCoin.T resource with value `amount` from the sender's // account. This will fail if the sender's balance is less than `amount`. coin = LibraAccount.withdraw_from_sender(move(amount)); // Move the LibraCoin.T resource into the account of `payee`. If there is no // account at the address `payee`, this step will fail LibraAccount.deposit(move(payee), move(coin)); // Every procedure must end in a `return`. The IR compiler is very literal: // it directly translates the source it is given. It will not do fancy // things like inserting missing `return`s. return; } 

此事务脚本有一个不幸的问题 - 如果地址下没有帐户,它将失败payee。我们将通过修改脚本来修复此问题,以便为payee尚不存在的帐户创建帐户。

// A small variant of the peer-peer payment example that creates a fresh
// account if one does not already exist.

import 0x0.LibraAccount; import 0x0.LibraCoin; main(payee: address, amount: u64) { let coin: R#LibraCoin.T; let account_exists: bool; // Acquire a LibraCoin.T resource with value `amount` from the sender's // account. This will fail if the sender's balance is less than `amount`. coin = LibraAccount.withdraw_from_sender(move(amount)); account_exists = LibraAccount.exists(copy(payee)); if (!move(account_exists)) { // Creates a fresh account at the address `payee` by publishing a // LibraAccount.T resource under this address. If theres is already a // LibraAccount.T resource under the address, this will fail. create_account(copy(payee)); } LibraAccount.deposit(move(payee), move(coin)); return; } 

让我们看一个更复杂的例子。在此示例中,我们将使用事务脚本来支付多个收件人而不只是一个。

// Multiple payee example. This is written in a slightly verbose way to
// emphasize the ability to split a `LibraCoin.T` resource. The more concise
// way would be to use multiple calls to `LibraAccount.withdraw_from_sender`.

import 0x0.LibraAccount; import 0x0.LibraCoin; main(payee1: address, amount1: u64, payee2: address, amount2: u64) { let coin1: R#LibraCoin.T; let coin2: R#LibraCoin.T; let total: u64; total = move(amount1) + copy(amount2); coin1 = LibraAccount.withdraw_from_sender(move(total)); // This mutates `coin1`, which now has value `amount1`. // `coin2` has value `amount2`. coin2 = LibraCoin.withdraw(&mut coin1, move(amount2)); // Perform the payments LibraAccount.deposit(move(payee1), move(coin1)); LibraAccount.deposit(move(payee2), move(coin2)); return; } 

这就结束了我们对事务脚本的“浏览”。有关更多示例,包括初始testnet中支持的事务脚本,请参阅libra/language/stdlib/transaction_scripts

编写模块

我们现在将注意力转向编写自己的Move模块,而不是仅重用现有模块LibraAccountLibraCoin模块。考虑这种情况:Bob将在未来的某个时刻在地址_a_创建一个帐户。Alice希望为Bob“收取”一些资金,以便他们可以在创建后将其提取到他的帐户中。但如果鲍勃从未创建帐户,她也希望能够为自己收回资金。

为了解决Alice的这个问题,我们将编写一个模块EarmarkedLibraCoin

  • 声明一个新的资源类型EarmarkedLibraCoin.T,用于包装Libra硬币和收件人地址。

  • 允许Alice创建此类型并在其帐户下发布(create程序)。

  • 允许Bob声明资源(claim_for_recipient过程)。

  • 允许任何人EarmarkedLibraCoin.T摧毁它并获得底层硬币(unwrap程序)。

    // A module for earmarking a coin for a specific recipient module EarmarkedLibraCoin { import 0x0.LibraCoin; // A wrapper containing a Libra coin and the address of the recipient the // coin is earmarked for. resource T { coin: R#LibraCoin.T, recipient: address } // Create a new earmarked coin with the given recipient. // Publish the coin under the transaction sender's account address. public create(coin: R#LibraCoin.T, recipient: address) { let t: R#Self.T; // Construct or "pack" a new resource of type T. Only procedures of the // EarmarkedCoin module can create an EarmarkedCoin.T. t = T { coin: move(coin), recipient: move(recipient), }; // Publish the earmarked coin under the transaction sender's account // address. Each account can contain at most one resource of a given type; // this call will fail if the sender already has a resource of this type. move_to_sender(move(t)); return; } // Allow the transaction sender to claim a coin that was earmarked for her. public claim_for_recipient(earmarked_coin_address: address): R#Self.T { let t: R#Self.T; let t_ref: &R#Self.T; let sender: address; // Remove the earmarked coin resource published under earmarked_coin_address. // If there is resource of type T published under the address, this will fail. t = move_from(move(earmarked_coin_address)); t_ref = &t; // This is a builtin that returns the address of the transaction sender. sender = get_txn_sender(); // Ensure that the transaction sender is the recipient. If this assertion // fails, the transaction will fail and none of its effects (e.g., // removing the earmarked coin) will be committed. 99 is an error code // that will be emitted in the transaction output if the assertion fails. assert(*(&move(t_ref).recipient) == move(sender), 99); return move(t); } // Allow the creator of the earmarked coin to reclaim it. public claim_for_creator(): R#Self.T { let t: R#Self.T; let coin: R#LibraCoin.T; let recipient: address; let sender: address; sender = get_txn_sender(); // This will fail if no resource of type T under the sender's address. t = move_from(move(sender)); return move(t); } // Extract the Libra coin from its wrapper and return it to the caller. public unwrap(t: R#Self.T): R#LibraCoin.T { let coin: R#LibraCoin.T; let recipient: address; // This "unpacks" a resource type by destroying the outer resource, but // returning its contents. Only the module that declares a resource type // can unpack it. T { coin, recipient } = move(t); return move(coin); } }

Alice可以通过创建一个调用createBob的地址_a_和LibraCoin.T她拥有的事务脚本为Bob创建一个专用硬币。一旦_一_被创建,鲍勃可以通过从发送交易权利要求的硬币_一个_。这会调用claim_for_recipient,将结果传递给unwrap,并将返回的内容存储LibraCoin在他希望的任何地方。如果Bob花费太长时间在_a_下创建一个帐户并且Alice想要收回她的资金,那么她可以通过使用claim_for_creator后续来完成unwrap

细心的读者可能已经注意到,该模块中的代码与内部结构无关LibraCoin.T。它可以像使用通用编程一样容易地编写(例如resource T<AnyResource: R> { coin: AnyResource, ... })。我们目前正致力于为Move添加对这种参数多态的支持。

未来的开发经验

在不久的将来,IR将稳定下来,编译和验证程序将变得更加用户友好。此外,将跟踪来自IR源的位置信息并将其传递给验证程序,以使错误消息更易于调试。但是,IR将继续作为测试Move字节码的工具。它意味着是底层字节码的语义透明表示。为了进行有效的测试,IR编译器必须生成错误的代码,这些代码将被字节码验证程序拒绝或在运行时在编译器中失败。用户友好的源语言会做出不同的选择; 它应该拒绝编译将在管道的后续步骤中失败的代码。

将来,我们将拥有更高级别的Move源语言。该源语言旨在安全轻松地表达常见的Move习语和编程模式。由于Move字节码是一种新语言,而Libra Blockchain是一种新的编程环境,我们对应该支持的习语和模式的理解仍在不断发展。源语言还处于开发的早期阶段,我们还没有发布它的时间表。

Libra国内开发者微信交流群:

Facebook币Libra学习不能入群请加管理微信,拉你进群=>Facebook币Libra学习

点赞
收藏
评论区
推荐文章
Easter79 Easter79
3年前
springboot+mybatis 使用事务
一、一些概念声明式的事务管理是基于AOP的,在springboot中可以通过@Transactional注解的方式获得支持,这种方式的优点是:1)非侵入式,业务逻辑不受事务管理代码的污染。2)方法级别的事务回滚,合理划分方法的粒度可以做到符合各种业务场景的事务管理。本文使用目前最常用的mybatis框架来配置springboot的事务
Wesley13 Wesley13
3年前
@Transactional 回滚不生效原因
事务的管理方式有两种,第一种是编程式事务管理,需要将数据库的自动提交等取消,并且需要自己编写事务代码,第二种则是声明式事务管理模式,spring利用springAOP特性编写了注解即题目中所提到的方式来管理事务,避免开发人员编写大量的事务代码。一、特性先来了解一下@Transactional注解的特性吧,可以更好排查问题1\.service类
Stella981 Stella981
3年前
Facebook的Libra “区块链”到底是如何运作的?
!(https://oscimg.oschina.net/oscnet/92bef84caf83cd4bc7a226e620de32a43ab.jpg)!(https://oscimg.oschina.net/oscnet/7ac531a3e0bdab14fb360a53b885ff4d6c8.jpg)本文深入研究了“关于FacebookL
Stella981 Stella981
3年前
FFmpeg开发实战(二):FFmpeg 文件操作
FFmpeg提供了丰富的API供我们使用,下面我们来讲述一下文件操作相关的API:FFmpeg删除文件:avpriv\_io\_delete()FFmpeg重命名文件:avpriv\_io\_move()FFmpeg打开目录:avio\_open\_dir()FFmpeg读取目录:avio\_read\_d
Easter79 Easter79
3年前
The Move To Linux
OneofthestandardsthathasbecomenormalintheUSfederalsectoristherequirementthatallmobiledevices,suchaslaptops,haveencrypteddrives.Thiswasadirectresultof
Easter79 Easter79
3年前
Spring事务——使用TransactionProxyFactoryBean创建事务代理
    Spring同时支持编程式事务策略和声明式事务策略,大部分时候,我们都推荐采用声明式事务策略。使用声明式事务策略的优势十分明显:声明式事务能大大降低开发者的代码书写量,而且声明式事务几乎不影响应用的代码。因此,不论底层事务策略如何变化,应用程序都无需任何改变应用程序代码无需任何事务处理代码,可以更专注于业务逻辑的实
Wesley13 Wesley13
3年前
Spring事务管理
Spring提供了一流的事务管理。在Spring中可以支持声明式事务和编程式事务。    本章主要目标如下:     1,Spring事务    2,事务属性    3,事务管理器    4,声明式事务      1.1Spring的事务     事务管理在应用程序中起着至关重要的作用:它是一系列任务
hashgame776 hashgame776
2年前
哈希竞猜游戏算法原理及特性说明hashgame776
PoH作为一种新的共识算法近期受到了较大的关注,而PooI验证池和PBFT则是联盟链和私链中较为常见的共识算法。1、PoH:即历史时间证明算法,旨在通过将时间本身编码到区块链中来减轻处理块中网络节点的负载。PoH采用创新的分片式时钟,将时间和状态解耦。简单来说就是将全局的时间链和每个区块的时间链分开,状态的更新不再需要全局时间的同步。PoH通过引入一个名叫信
京东云开发者 京东云开发者
10个月前
Spring事务实现原理
1、引言spring的springtx模块提供了对事务管理支持,使用spring事务可以让我们从复杂的事务处理中得到解脱,无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。spring事务有编程式事务和声明式事务两种实现方式。编程式事务是通过编写代
京东云开发者 京东云开发者
1个月前
Spring事务实现原理
作者:京东零售范锡军1、引言spring的springtx模块提供了对事务管理支持,使用spring事务可以让我们从复杂的事务处理中得到解脱,无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。spring事务有编程式事务和声明式事务两种实现方式。编