Facebook Libra - 第一筆交易

天邊的魚發表於2019-07-16

第一筆交易

假定

  • 執行的是Linux或者macOS系統
  • 網路連線正常
  • git已安裝
  • macOS中安裝了Homebrew
  • Linux中安裝了yum或者apt-get

提交一筆交易的步驟

  1. 克隆並構建Libra Core
  2. 構建Libra命令列客戶端並且連線到測試網路
  3. 建立Alice和Bob的賬戶
  4. 挖礦並新增到Alice與Bob的賬戶中
  5. 提交一筆交易

克隆並構建Libra Core

克隆Libra Core倉庫

git clone https://github.com/libra/libra.git

啟動Libra Core

切換到libra資料夾並且執行啟動指令碼來安裝依賴:

cd libra
./scripts/dev_setup.sh

這個安裝指令碼里面有以下幾步

  • 安裝rustup - rustup是一個Rust語言的安裝器,Libra Core就是用其實現的
  • 安裝rust-toolchain的正確版本
  • 安裝CMake - 管理構建過程
  • 安裝protoc - 一個protocol buffers的編譯器
  • 安裝Go - 構建protocol buffers

如果遇到問題,詳見解決問題

構建Libra命令列客戶端並且連線到測試網路

為了連線到Libra測試網路的驗證節點,按照如下方式執行客戶端

./scripts/cli/start_cli_testnet.sh

這條命令使用cargo(Rust的包管理器)來構建並執行客戶端,並把客戶端連線到測試網路上的一個驗證節點。

一旦客戶端連線到測試網路上的節點,你將會看到如下輸出。退出可以使用 quit 命令

usage: <command> <args>

Use the following commands:

account | a
  Account operations
query | q
  Query operations
transfer | transferb | t | tb
  <sender_account_address>|<sender_account_ref_id> <receiver_account_address>|<receiver_account_ref_id> <number_of_coins> [gas_unit_price (default=0)] [max_gas_amount (default 10000)] Suffix 'b' is for blocking.
  Transfer coins from account to another.
help | h
  Prints this help
quit | q!
  Exit this client


Please, input commands:

libra%

如果在構建客戶端與連線測試網時出現問題,詳見解決問題

注意:如果你想在本地執行一個驗證節點,按照這裡的操作進行:執行一個本地驗證節點

建立Alice和Bob的賬戶

一旦你的客戶端連線到了測試網,你就可以執行CLI命令來建立新賬戶了。我們將會為兩個使用者建立賬戶(就叫Alice和Bob吧)

第一步:檢查你的系統上是否執行著CLI客戶端

一個 libra% 的命令列字首說明你的Libra CLI客戶端正在執行中。按照下面這樣輸入“account”可以看到關於__account__命令的幫助資訊

libra% account
usage: account <arg>

Use the following args for this command:

create | c
  Create an account. Returns reference ID to use in other operations
list | la
  Print all accounts that were created or loaded
recover | r <file path>
  Recover Libra wallet from the file path
write | w <file name>
  Save Libra wallet mnemonic recovery seed to disk
mint | mintb | m | mb <receiver account> <number of coins>
  Mint coins to the account. Suffix 'b' is for blocking

第二步:建立Alice的賬戶

注意用CLI建立一個賬戶並不會更新到區塊鏈上,只是建立了一個本地的鑰匙對。

為了建立Alice的賬戶,輸入下面的命令:

libra% account create

成功的話輸出就像下面這樣:

>> Creating/retrieving next account from wallet
Created/retrieved account #0 address 3ed8e5fafae4147b2a105a0be2f81972883441cfaaadf93fc0868e7a0253c4a8

0#是Alice賬戶的索引,這個16進位制的字串就是Alice的賬戶地址。索引只是一種指向Alice賬戶的方式。賬戶索引可以讓使用者在其他的CLI命令中便捷地指向他們所建立賬戶的一個本地CLI索引。索引對於區塊鏈來說是沒什麼意義的。只有當通過挖礦或者他人轉賬方式,有資金轉入到Alice的賬戶的時候,Alice的賬戶才會在區塊鏈上面被建立。注意你可能使用了CLI中的16進位制地址。這個賬戶索引只是對於賬戶地址的一種便利的包裝而已。

第三步:建立Bob的賬戶

為了建立Bob的賬戶,重複下面的賬戶建立命令:

libra% account create

成功的話輸出就像下面這樣:

>> Creating/retrieving next account from wallet
Created/retrieved account #1 address 8337aac709a41fe6be03cad8878a0d4209740b1608f8a81566c9a7d4b95a2ec7

#1就是Bob的賬戶索引,這個16進位制字串就是Bob的賬戶。

第四步(可選):賬戶列表

輸入下面的命令可以列出你所建立的賬戶:

libra% account list

成功的話輸出就像下面這樣:

User account index: 0, address: 3ed8e5fafae4147b2a105a0be2f81972883441cfaaadf93fc0868e7a0253c4a8, sequence number: 0
User account index: 1, address: 8337aac709a41fe6be03cad8878a0d4209740b1608f8a81566c9a7d4b95a2ec7, sequence number: 0

這個賬戶的序列號(sequence number)代表的是從這個賬戶傳送的交易的數量。每當這個賬戶傳送了一筆交易被執行並且儲存到了區塊鏈中,這個數字就會增加。瞭解更多詳見序列號

給Alice和Bob的賬戶中新增Libra幣

在測試網上挖礦並給賬戶新增幣是通過Faucet完成的。Faucet是一個和測試網一同執行的服務。這個服務存在的目的只是為了促進測試網上的挖礦速度,而且主網是沒有的。它建立的Libra是沒有實際價值的。假定你已經建立了Alice和Bob的賬戶,各自的索引是0和1。那麼你可以按照下面的步驟來新增Libra到各個賬戶中

第一步:新增110Libra到Alice的賬戶中

為了挖取Libra並新增到Alice的賬戶中,輸入下面的命令:

libra% account mint 0 110
  • 0是Alice賬戶的索引
  • 110是新增到Alice賬戶中的Libra數量

一個成功的賬戶挖取命令同時會在區塊臉上建立Alice的賬戶。

成功的話輸出就像下面這樣:

>> Minting coins
Mint request submitted

注意當請求提交的時候,意味著它被成功地新增到了(測試網上的驗證節點的)記憶體池中。這並不意味著它就會被成功執行。後面,我們將會查詢賬戶餘額來確認挖礦是否成功。

如果你的賬戶挖礦命令沒有成功提交你的請求,詳見問題

第二步:新增52Libra到Bob的賬戶中

為了挖取Libra並新增到Bob的賬戶中,輸入下面的命令:

libra% account mint 1 51
  • 1是Bob賬戶的索引
  • 52是新增到Bob賬戶中的Libra數量
  • 一個成功的賬戶挖取命令同時會在區塊臉上建立Bob的賬戶。另一個在區塊鏈上建立Bob賬戶的方法是從Alice的賬戶向Bob的賬戶轉錢。

成功的話輸出就像下面這樣:

>> Minting coins
Mint request submitted

如果你的賬戶挖礦命令沒有成功提交你的請求,詳見問題

第三步:檢查餘額

輸入下面的命令檢查Alice的賬戶餘額:

libra% query balance 0

成功的話輸出就像下面這樣:

Balance is: 110

輸入下面的命令檢查Bob的賬戶餘額:

libra% query balance 1

成功的話輸出就像下面這樣:

Balance is: 52

提交交易

在我們提交從Libra到Bob賬戶的轉賬交易之前,我們先去查詢每個賬戶的序列號(sequence number)。這將幫助我們理解交易的執行是如果改變每個賬戶的序列號的。

查詢賬戶的序列號

libra% query sequence 0
>> Getting current sequence number
Sequence number is: 0
libra% query sequence 1
>> Getting current sequence number
Sequence number is: 0

query sequence 0 中,0是Alice賬戶的索引。0這個序列號說明到目前為止,Alice和Bob的賬戶都沒有傳送過交易。

轉賬

為了提交一筆從Alice到Bob的賬戶10和Libra的交易,輸入下面的命令:

libra% transfer 0 1 10
  • 0是Alice賬戶的索引
  • 1是Bob賬戶的索引
  • 10是Alice轉賬給Bob賬戶的Libra數量

成功的話輸出像下面這樣:

>> Transferring
Transaction submitted to validator
To query for transaction status, run: query txn_acc_seq 0 0 <fetch_events=true|false>

你可以使用 query txn_acc_seq 0 0 true (通過賬戶和序列號的交易)這條命令來追溯剛剛提交的交易的相關資訊。第一個引數是傳送者賬戶的本地索引,第二個引數是賬戶的序列號(sequence number)。

你剛剛向測試網上的驗證節點提交了一筆交易,它被包含在了驗證節點的記憶體池中。這並不意味著你的交易已經被執行了。理論上來說,如果系統太慢了或者負載太高,要看到結果需要一些時間,你可能需要檢查好多次賬戶資訊。為了查詢一個索引是0的賬戶,你可以使用 query account_state 0 這條命令。

關於相關的轉賬問題,可以看看問題

阻塞轉賬命令(The Blocking Transfer command): 可以使用 transferb 命令來代替 transfer 命令。 transferb 會提交交易並且只有當交易被提交到區塊鏈上的時候才會返回到客戶端提示符上。例子如下:

libra% transferb 0 1 10

交易的生命週期描述了一筆交易從提交到執行儲存的生命週期。

轉賬後查詢序列號(sequence number)

libra% query sequence 0
>> Getting current sequence number
Sequence number is: 1
libra% query sequence 1
>> Getting current sequence number
Sequence number is: 0

Alice賬戶(索引0)的序列號是1代表了到目前為止從Alice的賬戶發出了一筆交易。Bob賬戶(索引1)的序列號是0代表了到目前為止Bob的賬戶還沒有傳送過交易。每當一個賬戶傳送了一筆交易。它的序列號都會增加1。

轉賬後檢查賬戶的餘額

為了檢查兩個賬戶的餘額,再一次像上面一樣查詢餘額。如果交易成功執行,你將會看到Alice賬戶有100Libra同時Bob的賬戶有62Libra。

libra% query balance 0
Balance is: 100
libra% query balance 1
Balance is: 62

恭喜

你已經成功地在測試網上執行了一筆從Alice到Bob賬戶10個Libra的交易。

問題處理

啟動

  • 更新Rust:
    • 在libra資料夾中執行 rustup update
  • 更新protoc:
    • 更新protoc到3.6.0版本或者更高
  • 在libra資料夾中重新執行啟動指令碼
    • ./scripts/dev_setup.sh

客戶端構建與執行

如果出現了構建錯誤,嘗試移除libra資料夾的cargo的lock檔案

  • rm Cargo.lock

如果客戶端沒有連線到測試網:

  • 檢查網路連線
  • 確保使用了最新版本的客戶端。拉取最新的Libra Core並重新執行客戶端
    • ./scripts/cli/start_cli_testnet.sh

挖礦並新增錢款到賬戶

  • 如果你連線的測試網驗證節點不可用,你會得到一個"Server unavailable" (服務不可用)訊息,就像下面這樣:
libra% account mint 0 110
>> Minting coins
[ERROR] Error minting coins: Server unavailable, please retry and/or check **if** host passed to the client is running
  • 如果在交易提交之後你的餘額仍然沒有更新,等一會然後再去檢視餘額。如果區塊鏈中正在進行的交易很多的話可能會有一點的延遲。如果你的餘額還是沒有變化,嘗試著再去挖礦。
  • 為了檢查一個賬戶是否存在,需要查詢賬戶狀態。如果是一個索引是0的賬戶,輸入這個:
libra% query account_state 0

轉賬命令

如果(你的客戶端連線到的)測試網路節點不可用,或者連線超時,你會看到這樣的錯誤:

libra% transfer 0 1 10
>> Transferring
[ERROR] Failed to perform transaction: Server unavailable, please retry and/or check if host passed to the client is running

為了解決轉賬錯誤:

  • 檢查到測試網的網路連線
  • 檢查傳送者賬戶,確定它是存在的。對於索引是0的賬戶,使用下面的命令:
    • query account_state 0
  • 你可以使用 quit 或者 q 來嘗試退出客戶端,然後重新執行下面的命令來連線到測試網路
    • libra資料夾中執行 ./scripts/cli/start_cli_testnet.sh

額外查詢命令的樣例輸出

通過賬戶和序列號查詢交易

這個例子將會使用賬戶和序列號查詢一筆單獨的交易。

libra% query txn_acc_seq 0 0 true
>> Getting committed transaction by account and sequence number
Committed transaction: SignedTransaction {
 { raw_txn: RawTransaction {
    sender: 3ed8e5fafae4147b2a105a0be2f81972883441cfaaadf93fc0868e7a0253c4a8,
    sequence_number: 0,
    payload: {,
      transaction: peer_to_peer_transaction,
      args: [
        {ADDRESS: 8337aac709a41fe6be03cad8878a0d4209740b1608f8a81566c9a7d4b95a2ec7},
        {U64: 10000000},
      ]
    },
    max_gas_amount: 10000,
    gas_unit_price: 0,
    expiration_time: 1560466424s,
},
 public_key: 55af3fe3f28550a2f1e5ebf073ef193feda44344d94c463b48be202aa0b3255d,
 signature: Signature( R: CompressedEdwardsY: [210, 23, 214, 62, 228, 179, 64, 147, 81, 159, 180, 138, 100, 211, 111, 139, 178, 148, 81, 1, 240, 135, 148, 145, 104, 234, 227, 239, 198, 153, 13, 199], s: Scalar{
  bytes: [203, 76, 105, 49, 64, 130, 162, 81, 22, 237, 159, 26, 80, 181, 111, 94, 84, 6, 152, 126, 181, 192, 62, 103, 130, 94, 246, 174, 139, 214, 3, 15],
} ),
 }
 }
Events:
ContractEvent { access_path: AccessPath { address: 3ed8e5fafae4147b2a105a0be2f81972883441cfaaadf93fc0868e7a0253c4a8, type: Resource, hash: "217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc97", suffix: "/sent_events_count/" } , index: 0, event_data: AccountEvent { account: 8337aac709a41fe6be03cad8878a0d4209740b1608f8a81566c9a7d4b95a2ec7, amount: 10000000 } }
ContractEvent { access_path: AccessPath { address: 8337aac709a41fe6be03cad8878a0d4209740b1608f8a81566c9a7d4b95a2ec7, type: Resource, hash: "217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc97", suffix: "/received_events_count/" } , index: 0, event_data: AccountEvent { account: 3ed8e5fafae4147b2a105a0be2f81972883441cfaaadf93fc0868e7a0253c4a8, amount: 10000000 } }

注意交易數量使用 microlibra(應該是libra的一種計量單位) 展示的。

查詢結果

在下面的這個例子中,我們將會查詢索引為0這個賬戶的"sent"事件。你會注意到在我們從這個賬戶傳送了一筆賬戶之後會有一個事件。當前狀態的證明(proof)也被返回了,因此可以驗證沒有丟失事件 - 當查詢沒有返回"limit"事件的時候會完成此事件。

libra% query event 0 sent 0 true 10
>> Getting events by account and event type.
EventWithProof {
  transaction_version: 3,
  event_index: 0,
  event: ContractEvent { access_path: AccessPath { address: e7460e02058b36d28e8eef03f0834c605d3d6c57455b8ec9c3f0a3c8b89f248b, type: Resource, hash: "217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc97", suffix: "/sent_events_count/" } , index: 0, event_data: AccountEvent { account: 46efbad798a739c088e0e98dd9d592c27c7eb45ba1f8ccbdfc00bd4d7f2947f3, amount: 10000000 } },
  proof: EventProof { ledger_info_to_transaction_info_proof: AccumulatorProof { siblings: [HashValue(62570ae9a994bcb20c03c055667a4966fa50d0f17867dd5819465072fd2c58ba), HashValue(cce2cf325714511e7d04fa5b48babacd5af943198e6c1ac3bdd39c53c87cb84c)] }, transaction_info: TransactionInfo { signed_transaction_hash: HashValue(69bed01473e0a64140d96e46f594bc4b463e88e244b694e962b7e19fde17f30d), state_root_hash: HashValue(5809605d5eed94c73e57f615190c165b11c5e26873012285cc6b131e0817c430), event_root_hash: HashValue(645df3dee8f53a0d018449392b8e9da814d258da7346cf64cd96824f914e68f9), gas_used: 0 }, transaction_info_to_event_proof: AccumulatorProof { siblings: [HashValue(5d0e2ebf0952f0989cb5b38b2a9b52a09e8d804e893cb99bf9fa2c74ab304bb1)] } }
}
Last event state: Some(
    AccountStateWithProof {
        version: 3,
        blob: Some(
            AccountStateBlob {
             Raw: 0x010000002100000001217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc974400000020000000e7460e02058b36d28e8eef03f0834c605d3d6c57455b8ec9c3f0a3c8b89f248b00e1f50500000000000000000000000001000000000000000100000000000000
             Decoded: Ok(
                AccountResource {
                    balance: 100000000,
                    sequence_number: 1,
                    authentication_key: 0xe7460e02058b36d28e8eef03f0834c605d3d6c57455b8ec9c3f0a3c8b89f248b,
                    sent_events_count: 1,
                    received_events_count: 0,
                },
            )
             },
        ),
        proof: AccountStateProof {
            ledger_info_to_transaction_info_proof: AccumulatorProof {
                siblings: [
                    HashValue(62570ae9a994bcb20c03c055667a4966fa50d0f17867dd5819465072fd2c58ba),
                    HashValue(cce2cf325714511e7d04fa5b48babacd5af943198e6c1ac3bdd39c53c87cb84c),
                ],
            },
            transaction_info: TransactionInfo {
                signed_transaction_hash: HashValue(69bed01473e0a64140d96e46f594bc4b463e88e244b694e962b7e19fde17f30d),
                state_root_hash: HashValue(5809605d5eed94c73e57f615190c165b11c5e26873012285cc6b131e0817c430),
                event_root_hash: HashValue(645df3dee8f53a0d018449392b8e9da814d258da7346cf64cd96824f914e68f9),
                gas_used: 0,
            },
            transaction_info_to_account_proof: SparseMerkleProof {
                leaf: Some(
                    (
                        HashValue(c0fbd63b0ae4abfe57c8f24f912f164ba0537741e948a65f00d3fae0f9373981),
                        HashValue(fc45057fd64606c7ca40256b48fbe486660930bfef1a9e941cafcae380c25871),
                    ),
                ),
                siblings: [
                    HashValue(4136803b3ba779bb2c1daae7360f3f839e6fef16ae742590a6698b350a5fc376),
                    HashValue(5350415253455f4d45524b4c455f504c414345484f4c4445525f484153480000),
                    HashValue(a9a6bda22dd6ee78ddd3a42da152b9bd39797b7da738e9d6023f407741810378),
                ],
            },
        },
    },
)

查詢賬戶狀態

在這個賬戶中,我們將會查詢一個賬戶的狀態。

libra% query account_state 0
>> Getting latest account state
Latest account state is:
 Account: 3ed8e5fafae4147b2a105a0be2f81972883441cfaaadf93fc0868e7a0253c4a8
 State: Some(
    AccountStateBlob {
     Raw: 0x010000002100000001217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc9744000000200000003ed8e5fafae4147b2a105a0be2f81972883441cfaaadf93fc0868e7a0253c4a800e1f50500000000000000000000000001000000000000000100000000000000
     Decoded: Ok(
        AccountResource {
            balance: 100000000,
            sequence_number: 1,
            authentication_key: 0x3ed8e5fafae4147b2a105a0be2f81972883441cfaaadf93fc0868e7a0253c4a8,
            sent_events_count: 1,
            received_events_count: 0,
        },
    )
     },
)
 Blockchain Version: 3

執行一個本地的驗證節點

為了在你的電腦上啟動一個本地的驗證節點並建立你自己本地的區塊鏈網路(沒有連線到Libra測試網路),需要確保你已經執行了之前所說的構建指令碼,變更到Libra Core倉庫的根路徑,然後執行 libra_swarm ,就像下面這樣:

$ cd ~/libra
$ cargo run -p libra_swarm -- -s

-p libra_swarm 是cargo開始執行 libra_swarm 包,這樣會啟動一個包含一個節點的本地區塊鏈。

-s 選項啟動一個連線到本地區塊鏈上的本地客戶端

為了看到開啟節點與連線到Libra區塊臉上的額外選項,執行:

$ cargo run -p libra_swarm -- -h

cargo執行命令可能需要一些時間來執行。如果這條命令的執行了且沒有錯誤,那麼一個Libra CLI客戶端的例項和一個本地的驗證節點就已經執行在你的系統中了。在成功執行的基礎上,你將會看到包含著CLI客戶端選單和 libra 提示符的輸出。

交易的生命週期

一旦你已經完成了你的第一筆交易,你可以去看看 交易的生命週期 的文件了,目的在於:

  • 深入瞭解交易從提交到執行的過程。
  • 瞭解在交易在Libra生態系統中提交與執行過程中,Libra驗證器的各個邏輯元件之間的互動。

相關文章