本文描述如何在Move中间表示(IR)中编写事务脚本和模块。IR是即将到来的Move源代码语言的早期(且不稳定)先驱。Move IR是一个覆盖于Move字节码之上的薄薄的语法层,用于测试字节码验证器和虚拟机,它对开发人员不是特别友好。它的级别足够高,可以编写人类可读的代码,但又足够低,可以直接编译以移动字节码。

Move IR 示例代码解读

本文描述如何在Move中间表示(IR)中编写事务脚本和模块。IR是即将到来的Move源代码语言的早期(且不稳定)先驱。Move IR是一个覆盖于Move字节码之上的薄薄的语法层,用于测试字节码验证器和虚拟机,它对开发人员不是特别友好。它的级别足够高,可以编写人类可读的代码,但又足够低,可以直接编译以移动字节码。

接下来,我将展示一些Move IR片段,并尽可能的阐述他们的含义

编写事务脚本

正如我们在Move事务脚本中解释的那样,用户编写事务脚本来请求对Libra

LibraAccount模块分析

//这个模块主要是很对账户资源的,用于管理每个Libra账户 //可以看到他引用了 module LibraAccount {     import 0x0.LibraCoin;     import 0x00.Hash;      //每个Libra账户都有一个LibraAccount.T资源     // Every Libra account has a LibraLibraAccount.T resource     resource T {         // The coins stored in this account         balance: R#LibraCoin.T,         //当前的身份认证key         //这个key可以与创建账户的key不同         authentication_key: bytearray,         //账户nonce         sequence_number: u64,         //临时的发送交易事件计数器,等到后面事件系统被完善后,这个值应该会被代替         sent_events_count: u64,         //临时的交易接收事件计数器,等到后面事件系统被完善后,这个值应该会被代替         received_events_count: u64     }      // Message for sent events     struct SentPaymentEvent {         // The address that was paid         payee: address,         // The amount of LibraCoin.T sent         amount: u64,     }      // Message for received events     struct ReceivedPaymentEvent {         // The address that sent the coin         payer: address,         // The amount of LibraCoin.T received         amount: u64,     }      //创建一个新的LibraAccount.T类型的资源     //这个过程被内置模块create_account调用     make(auth_key: bytearray): R#Self.T {         let zero_balance: R#LibraCoin.T;         zero_balance = LibraCoin.zero();         return T {             balance: move(zero_balance),             authentication_key: move(auth_key),             sequence_number: 0,             sent_events_count: 0,             received_events_count: 0,         };     }      // 向payee账户存入to_deposit资源     public deposit(payee: address, to_deposit: R#LibraCoin.T) {         let deposit_value: u64;         let payee_account_ref: &mut R#Self.T;         let sender: address;         let sender_account_ref: &mut R#Self.T;         let sent_event: V#Self.SentPaymentEvent;         let received_event: V#Self.ReceivedPaymentEvent;          // Check that the `to_deposit` coin is non-zero         deposit_value = LibraCoin.value(&to_deposit);         assert(copy(deposit_value) > 0, 7);          // Load the sender's account         sender = get_txn_sender();         sender_account_ref = borrow_global<T>(copy(sender));         // Log a send event         sent_event = SentPaymentEvent { payee: copy(payee), amount: copy(deposit_value) };         // 目前的打印事件只是临时之举,未来应该会变得更加有条理         emit_event(&mut move(sender_account_ref).sent_events_count, b"73656E745F6576656E74735F636F756E74", move(sent_event));          // Load the payee's account         payee_account_ref = borrow_global<T>(move(payee));         // Deposit the `to_deposit` coin         LibraCoin.deposit(&mut copy(payee_account_ref).balance, move(to_deposit));         // Log a received event         received_event = ReceivedPaymentEvent { payer: move(sender), amount: move(deposit_value) };         // TEMPORARY The events system is being overhauled and this will be replaced by something         // more principled in the future         emit_event(&mut move(payee_account_ref).received_events_count, b"72656365697665645F6576656E74735F636F756E74", move(received_event));         return;     }      //mint_to-address 只能被又有mint能力的的账户使用(参照LibraCoin模块)     //这些帐户将被收取gas费用。如果这些帐户没有足够的gas支付,则mint失败     // 那些账户也可以mint给自己coin     public mint_to_address(payee: address, amount: u64) {         let mint_capability_ref: &R#LibraCoin.MintCapability;         let coin: R#LibraCoin.T;         let payee_account_ref: &mut R#Self.T;         let payee_exists: bool;         let sender: address;          // Mint the coin         mint_capability_ref = LibraCoin.borrow_sender_mint_capability();         coin = LibraCoin.mint(copy(amount), move(mint_capability_ref));          // Create an account if it does not exist         payee_exists = exists<T>(copy(payee));         if (!move(payee_exists)) {             //这一行感觉没必要             sender = get_txn_sender();             Self.create_new_account(copy(payee), 0);         }          // Deposit the minted `coin`         Self.deposit(move(payee), move(coin));         return;     }      // Helper to withdraw `amount` from the given `account` and return the resulting LibraCoin.T     withdraw_from_account(account: &mut R#Self.T, amount: u64): R#LibraCoin.T {         let to_withdraw: R#LibraCoin.T;         to_withdraw = LibraCoin.withdraw(&mut move(account).balance, copy(amount));         return move(to_withdraw);     }      // Withdraw `amount` LibraCoin.T from the transaction sender's account     public withdraw_from_sender(amount: u64): R#LibraCoin.T {         let sender: address;         let sender_account: &mut R#Self.T;         let to_withdraw: R#LibraCoin.T;          // Load the sender         sender = get_txn_sender();         sender_account = borrow_global<T>(move(sender));          // Withdraw the coin         to_withdraw = Self.withdraw_from_account(move(sender_account), move(amount));         return move(to_withdraw);     }      //从发送者账户转移资金到接受者,如果发送者账户不存在,先创建账户,然后再调用此过程     public pay_from_sender(payee: address, amount: u64) {         let to_pay: R#LibraCoin.T;         let payee_exists: bool;         payee_exists = exists<T>(copy(payee));         if (move(payee_exists)) {             to_pay = Self.withdraw_from_sender(move(amount));             Self.deposit(move(payee), move(to_pay));         } else {             Self.create_new_account(move(payee), move(amount));         }         return;     }      //更新交易发送者身份认证key     //新的key将会被用于交易签名     public rotate_authentication_key(new_authentication_key: bytearray) {         let sender: address;         let sender_account: &mut R#Self.T;         sender = get_txn_sender();         sender_account = borrow_global<T>(move(sender));         *(&mut move(sender_account).authentication_key) = move(new_authentication_key);         return;     }      //创建一个新的账户,如果初始资金>0,则从交易发送者账户转移资金到新账户     public create_new_account(fresh_address: address, initial_balance: u64) {         create_account(copy(fresh_address));         if (copy(initial_balance) > 0) {             Self.pay_from_sender(move(fresh_address), move(initial_balance));         }         return;     }      // Helper to return u64 value of the `balance` field for given `account`     balance_for_account(account: &R#Self.T): u64 {         let balance_value: u64;         balance_value = LibraCoin.value(&move(account).balance);         return move(balance_value);     }      // Return the current balance of the LibraCoin.T in LibraLibraAccount.T at `addr`     public balance(addr: address): u64 {         let payee_account: &mut R#Self.T;         let imm_payee_account: &R#Self.T;         let balance_amount: u64;         //从账户地址,拿到LibraAccount类型的资源,此时拿到的资源是可变的         payee_account = borrow_global<T>(move(addr));         //将资源转为不可变资源,防止误操作         imm_payee_account = freeze(move(payee_account));         balance_amount = Self.balance_for_account(move(imm_payee_account));         return move(balance_amount);     }      // Helper to return the sequence number field for given `account`     sequence_number_for_account(account: &R#Self.T): u64 {         return *(&move(account).sequence_number);     }      // Return the current sequence number at `addr`     public sequence_number(addr: address): u64 {         let account_ref: &mut R#Self.T;         let imm_ref: &R#Self.T;         let sequence_number_value: u64;         account_ref = borrow_global<T>(move(addr));         imm_ref = freeze(move(account_ref));         sequence_number_value = Self.sequence_number_for_account(move(imm_ref));         return move(sequence_number_value);     }      // Checks if an account exists at `check_addr`     public exists(check_addr: address): bool {         let is_present: bool;         is_present = exists<T>(move(check_addr));         return move(is_present);     }      // 序言过程在每笔交易开始的时候被调用,它要做以下验证:     //账户的身份key是否匹配交易的公钥     //账户是否有足够的金额支付所有的gas     //sequence number是否匹配当前账户sequence key     prologue() {         let transaction_sender: address;         let transaction_sender_exists: bool;         let sender_account: &mut R#Self.T;         let imm_sender_account: &R#Self.T;         let sender_public_key: bytearray;         let public_key_hash: bytearray;         let gas_price: u64;         let gas_units: u64;         let gas_fee: u64;         let balance_amount: u64;         let sequence_number_value: u64;         let transaction_sequence_number_value: u64;          transaction_sender = get_txn_sender();          // 现在这些error code还是很不友好的,后续应该会变得更好         transaction_sender_exists = exists<T>(copy(transaction_sender));         assert(move(transaction_sender_exists), 5);          // Load the transaction sender's account         sender_account = borrow_global<T>(copy(transaction_sender));          //检查交易的公钥是否与当前账户的身份key相匹配         sender_public_key = get_txn_public_key();         public_key_hash = Hash.sha3_256(move(sender_public_key));         assert(move(public_key_hash) == *(&copy(sender_account).authentication_key), 2);          // 检查是否有足够的余额支付交易手续费         gas_price = get_txn_gas_unit_price();         gas_units = get_txn_max_gas_units();         //先计算最大所需的手续费,在交易结束后进行扣除真实消耗的gas手续费         gas_fee = move(gas_price) * move(gas_units);         imm_sender_account = freeze(copy(sender_account));         balance_amount = Self.balance_for_account(move(imm_sender_account));         assert(move(balance_amount) >= move(gas_fee), 6);          // 检查交易的sequence number是否与账户保存的sequence number匹配         sequence_number_value = *(&mut move(sender_account).sequence_number);         transaction_sequence_number_value = get_txn_sequence_number();         //这里多判断一次可能是未来防止并行交易的时候较大sequence number可以被接受         assert(copy(transaction_sequence_number_value) >= copy(sequence_number_value), 3);         assert(move(transaction_sequence_number_value) == move(sequence_number_value), 4);         return;     }      // 收尾主要是被用于在交易结束后进行一些处理     //主要是计算交易真实消耗gas的手续费和调整账户sequence number     // The epilogue is invoked at the end of transactions.     // It collects gas and bumps the sequence number     epilogue() {         let transaction_sender: address;         let sender_account: &mut R#Self.T;         let imm_sender_account: &R#Self.T;         let gas_price: u64;         let gas_units_remaining: u64;         let starting_gas_units: u64;         let gas_fee_amount: u64;         let balance_amount: u64;         let gas_fee: R#LibraCoin.T;         let transaction_sequence_number_value: u64;          transaction_sender = get_txn_sender();          // Load the transaction sender's account         sender_account = borrow_global<T>(copy(transaction_sender));          //收取真实消耗的gas的手续费         gas_price = get_txn_gas_unit_price();         starting_gas_units = get_txn_max_gas_units();         gas_units_remaining = get_gas_remaining();         gas_fee_amount = move(gas_price) * (move(starting_gas_units) - move(gas_units_remaining));         imm_sender_account = freeze(copy(sender_account));         balance_amount = Self.balance_for_account(move(imm_sender_account));         assert(move(balance_amount) >= copy(gas_fee_amount), 6);          gas_fee = Self.withdraw_from_account(copy(sender_account), move(gas_fee_amount));        //销毁掉相应的手续费资源        LibraCoin.TODO_REMOVE_burn_gas_fee(move(gas_fee));          // 账户sequence number + 1         transaction_sequence_number_value = get_txn_sequence_number();         *(&mut move(sender_account).sequence_number) = move(transaction_sequence_number_value) + 1;         return;     }  }

到这里整个move语言官方给出的实例代码就解读完毕了,读者也可以查看libra仓库看看最新更新的代码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注