美文网首页
libra: 从Move语言开始

libra: 从Move语言开始

作者: yangzming | 来源:发表于2020-11-16 18:50 被阅读0次

    从Move语言开始

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

    如果需要更深入的学习,可以参考Move技术白皮书了解更多细节:https://developers.libra.org/docs/move-paper

    在最初的testnet发行版中不支持自定义Move程序,但是可以在本地尝试这些特性。

    Move的关键特性

    Move交易脚本使能可编程交易

    • Libra的每个交易都包含一个Move交易脚本,该脚本对验证器代表客户端执行的逻辑进行编码(例如,将Libra币从Alice的帐户转移到Bob的帐户)。
    • 交易脚本通过调用一个或多个Move模块的过程,与Libra区块链全局存储中发布的Move资源进行交互。
    • 交易脚本不存储在全局状态中,其他交易脚本不能调用它。它是一个单一用途的程序。

    Move模块允许组合智能合约

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

    • 模块同时声明结构类型(包括资源,这是一种特殊类型的结构)和过程。
    • Move模块的过程定义了创建、访问和销毁它声明的类型的规则。
    • 模块是可重用的。在一个模块中声明的结构类型可以使用在另一个模块中声明的结构类型,在一个模块中声明的过程可以调用在另一个模块中声明的公共过程。模块可以调用在其他Move模块中声明的过程。交易脚本可以调用已发布模块的任何公共过程。
    • 最终,我们希望Libra用户能够在他们自己的账户下发布模块。

    Move拥有一流的资源

    • Move的关键特性是能够定义自定义资源类型。资源类型用于对具有丰富可编程性的安全数字资产进行编码。
    • 资源在语言中是普通的值。它们可以作为数据结构存储,作为参数传递给过程,从过程返回,等等。
    • Move类型系统为资源提供了特殊的安全保证。Move资源永远不能被复制、重用或丢弃。资源类型只能由定义该类型的模块创建或销毁。这些保证是由Move虚拟机通过字节码验证来静态执行的。Move虚拟机将拒绝运行没有通过字节码验证器的代码。
    • 所有Libra的货币都使用通用的Libra类型。例如:LBR货币表示为Libra<LBR>,假设美元货币表示为Libra<USD>Libra在语言中没有特殊的地位;每个Move资源都受到同样的保护。

    Move:在底层

    Move源语言

    本节描述如何用Move源语言编写交易脚本和模块。将继续展示一些带有大量注释的Move代码片段。README文件 libra/language/README.mdlibra/language/move-lang/README.md解释了如何去做。

    写交易脚本

    正如我们在Move交易脚本允许可编程的交易中解释的那样,用户编写交易脚本来请求更新Libra区块链的全局存储。有两个重要的构建块会出现在几乎所有的交易脚本中:LibraAccountLibra资源类型。

    当我们说一个用户“在Libra区块链上有一个地址0xff的帐户”时,我们的意思是地址0xff持有LibraAccount资源的一个实例。每个非空地址都有一个LibraAccount资源。这个资源存储帐户数据,如序列号、身份验证密钥和余额。Libra系统的任何部分,想要与一个帐户进行交互,必须从LibraAccount资源读取数据或调用LibraAccount模块的过程来完成。

    帐户余额是LibraAccount::balance类型的通用资源。(LibraAccount是模块的名称,Balance是该模块声明的资源的名称,LibraAccount资源除外。)一个单独的Libra账户可能持有多种货币的余额。例如,同时持有LBR和USD的帐户将拥有LibraAccount::Balance<LBR>资源和LibraAccount::Balance<USD>资源。但是,每个帐户必须至少有一个余额。

    Balance<Token>资源持有Libra<Token>类型的资源。这是Libra币的一般类型。这种类型是语言中的“一等公民”,就像任何其他Move资源一样。Libra类型的资源可以存储在程序变量中,在过程之间传递,等等。

    有兴趣的读者可以查看LibraAccountLibra模块中Libra/language/stdlib/modules/目录下的这两个关键资源的Move定义。

    以下是程序员如何在交易脚本中与这些模块和资源交互。

    // Simple peer-peer payment example.
    
    script {
    // Use the LibraAccount module published on the blockchain at account address
    // 0x0...1. 0x1 is shorthand that the language pads out to
    // 16 bytes by adding leading zeroes.
    use 0x1::LibraAccount;
    // Use the LBR resource from the LBR module. Naming the resource here makes
    // it possible to reference the resource without the module name.
    use 0x1::LBR::LBR;
    
    fun peer_to_peer_lbr_payment(payer: &signer, payee: address, amount: u64) {
      // Acquire the capability to withdraw from the payer's account.
      let payer_withdrawal_cap = LibraAccount::extract_withdraw_capability(payer);
      // Withdraw a value of `amount` LBR from the payer's account and deposit
      // it into the account at the address `payee`. This will fail if the
      // payer's balance is less than `amount` or if there is no account at the
      // address `payee`. The `metadata` and `metadata_signature` arguments are
      // not specified, so this could also fail if the transaction requires
      // that information.
      LibraAccount::pay_from<LBR>(&payer_withdrawal_cap, payee, amount, x"", x"");
      // Restore the capability back to the payer's account.
      LibraAccount::restore_withdraw_capability(payer_withdrawal_cap);
    }
    }
    

    更多的例子,包括在初始测试网中支持的交易脚本,参考libra/language/stdlib/transaction_scripts

    写模块

    现在我们将把注意力转向编写我们自己的Move模块,而不是仅仅重用现有的LibraAccountLibra模块。考虑这样一种情况:Bob打算在将来某个时候在地址a上创建一个帐户。Alice想“指定”一些她的币给Bob,这样他就可以在它创建后把它们转入自己的账户。但她也希望能够从她的币中移除专项拨款,例如,如果Bob从来没有创建帐户。

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

    • 声明了一个新的资源类型EarmarkedLibra,它包含LIbra和收件人地址。
    • 允许Alice创建这样的类型并在她的帐户下发布它(创建过程)。
    • 允许Bob声明资源(claim_for_recipient过程)。
    • 允许任何拥有EarmarkedLibra的人销毁它并获得下面的币(unwrap过程)。
    // The address where the module will be published:
    address 0xcc2219df031a68115fad9aee98e051e9 {
    
    // A module for earmarking a coin for a specific recipient
    module EarmarkedLibraCoin {
      use 0x1::Libra::Libra;
      use 0x1::Signer;
    
      // A wrapper containing a generic Libra and the address of the recipient the
      // coin is earmarked for.
      resource struct EarmarkedLibraCoin<Token> {
        coin: Libra<Token>,
        recipient: address
      }
    
      // Error codes
      const EWRONG_RECIPIENT: u64 = 0;
    
      // Create a new earmarked coin with the given `recipient`.
      // Publish the coin under the transaction sender's account address.
      public fun create<Token>(sender: &signer, coin: Libra<Token>, recipient: address) {
        // Construct or "pack" a new EarmarkedLibraCoin resource. Only procedures of the
        // `EarmarkedLibraCoin` module can create that resource.
        let t = EarmarkedLibraCoin { coin, 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, t);
      }
    
      // Allow the transaction sender to claim a coin that was earmarked for her.
      public fun claim_for_recipient<Token>(
        sender: &signer,
        earmarked_coin_address: address
      ): Libra<Token> acquires EarmarkedLibraCoin {
        // Remove the earmarked coin resource published under `earmarked_coin_address`
        // and "unpack" it to remove `coin and `recipient`.
        // If there is no resource of type EarmarkedLibraCoin<Token> published under
        // the address, this will fail.
        let EarmarkedLibraCoin { coin, recipient } =
          move_from<EarmarkedLibraCoin<Token>>(earmarked_coin_address);
    
        // 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.
        assert(recipient == Signer::address_of(sender), EWRONG_RECIPIENT);
    
        // Return the coin
        coin
      }
    
      // Allow the creator of the earmarked coin to reclaim it.
      public fun claim_for_creator<Token>(
        sender: &signer
      ): Libra<Token> acquires EarmarkedLibraCoin {
        let EarmarkedLibraCoin { coin, recipient:_ } =
          move_from<EarmarkedLibraCoin<Token>>(Signer::address_of(sender));
        coin
      }
    }
    }
    

    Alice可以创建一个交易脚本来为Bob创建一个指定的币,该交易脚本在Bob的地址a和她拥有的一个Libra上调用create。一旦创建了a, Bob就可以通过从a发送一个事务来获取币。这会调用claim_for_recipient来为Bob获取一个Libra,Bob可以存储在他想要的任何地址中。如果Bob花了很长时间在a下创建一个帐户,而Alice想要从她的币中删除专用标记,她可以通过使用claim_for_creator来完成。

    相关文章

      网友评论

          本文标题:libra: 从Move语言开始

          本文链接:https://www.haomeiwen.com/subject/wmpzbktx.html