合约的生命周期
To get a deeper understanding of the lifecycle of a Libra transaction, we will follow a transaction on its journey from being submitted to a Libra validator to being committed to the Libra Blockchain. We will then “zoom-in” on each logical component of a validator and take a look at its interactions with other components.
Client Submits a Transaction
A Libra client constructs a raw transaction (let us call it T5raw) to transfer 10 Libra from Alice’s account to Bob’s account. The raw transaction includes the following fields. Each field is linked to its glossary definition.
- Alice's account address.
- A program that indicates the actions to be performed on Alice's behalf. It contains:
- A Move bytecode peer-to-peer transaction script.
- A list of inputs to the script (for this example, Bob's account address and the amount of payment).
- Gas price (in microlibra/gas units) — The amount Alice is willing to pay per unit of gas, to execute the transaction. Gas is a way to pay for computation and storage. A gas unit is an abstract measurement of computation with no inherent real-world value.
- Maximum gas amount Alice is willing to pay for this transaction.
- Expiration time of the transaction.
- Sequence number — 5
- A transaction with sequence number 5 can only be applied to an account with sequence number 5.
The client signs transaction T5raw with Alice's private key. The signed transaction T5 includes the following:
- The raw transaction.
- Alice's public key.
- Alice's signature.
Assumptions
To describe the lifecycle of transaction T5, we will assume that:
- Alice and Bob have accounts on the Libra Blockchain.
- Alice's account has 110 Libra.
- The current sequence number of Alice's account is 5 (which indicates that 5 transactions have already been sent from Alice's account).
- There are a total of 100 validators — V1 to V100 on the network.
- The client submits transaction T5 to validator V1
- Validator V1 is a proposer/leader for the current round.
Lifecycle of the Transaction
In this section, we will describe the lifecycle of transaction T5, from being submitted by the client to being committed to the Libra Blockchain.
Where relevant, and following a numbered step in the lifecycle, we have provided a link to the corresponding inter-component interactions of the validator node. After you are familiar with all the steps in the lifecycle of the transaction, you may want to refer to the information on the corresponding inter-component interactions for each step.
Figure 1.1 Lifecycle of a Transaction
Accepting the Transaction
1 — The client submits transaction T5 to validator V1 whose admission control (AC) component receives the transaction. (Client → AC Sharing the Transaction With Other Validators
4 — The mempool will hold T5 in an in-memory buffer. Mempool may already contain multiple transactions sent from Alice's address.
5 — Using the shared-mempool protocol, V1 will share the transactions (including T5) in its mempool with other validators (V2 to V100) and place transactions received from the other validators into its own mempool. (Mempool → Other Validators Proposing the Block
6 — As validator V1 is a proposer/leader, it will pull a block of transactions from its mempool and replicate this block as a proposal to other validators via its consensus component. (Consensus → Mempool Executing the Block and Reaching Consensus
8 — As part of reaching agreement, the block of transactions (containing T5) is passed to the execution component. (Consensus → Execution Committing the Block
12 — If the block's execution result is agreed upon and signed by a set of validators that have the super-majority of votes, validator V1's execution component reads the result of the block execution from the speculative execution cache and commits all the transactions in the block to persistent storage. (Consensus → Execution Validator Component Interactions
In the Admission Control (AC)
Figure 1.2 Admission Control
Admission Control is the sole external interface of the validator. Any request made by a client to the validator goes to AC first.
Client → AC (AC.1)
A client submits a transaction to the admission control of a validator VX. This is done via: AC::SubmitTransaction()
.
AC → VM (AC.2)
Admission control accesses the virtual machine (VM) of the validator to perform preliminary checks on the transaction in order to reject malformed transactions early. This is done via: AC → Mempool (AC.3)
Once VM::ValidateTransaction()
returns without errors, AC forwards the transaction to validator VX's mempool via Mempool::AddTransactionWithValidation().
The mempool for validator VX will accept the transaction TN from the AC only if the sequence number of TN is greater than or equal to the current sequence number of the sender's account (note that the transaction will not be passed to consensus until it is the next sequence number).
AC → Storage (AC.4)
When the client performs a read query on the Libra Blockchain (for example, to get the balance of Alice's account), AC interacts with the storage component directly to obtain the requested information.
Admission Control README
For implementation details refer to the Admission Control README.
Virtual Machine (VM)
Figure 1.3 Virtual Machine
The Move virtual machine (VM) verifies and executes transaction scripts written in Move bytecode.
AC → VM (VM.1)
When admission control of validator VX receives a transaction from a client, it invokes VM::ValidateTransaction()
on the VM to validate the transaction.
VM → Storage (VM.2)
When AC or mempool request the VM to validate a transaction via VM::ValidateTransaction()
, the VM loads the transaction sender's account from storage and performs the following verifications:
- Checks that the input signature on the signed transaction is correct (to reject incorrectly signed transactions).
- Checks that the sender's account authentication key is the same as the hash of the public key (corresponding to the private key used to sign the transaction).
- Verifies that the sequence number for the transaction is not less than the current sequence number for the sender's account. Doing this check prevents the replay of the same transaction against the sender's account.
- Verifies that the program in the signed transaction is not malformed, as a malformed program cannot be executed by the VM.
- Verifies that there is sufficient balance in the sender's account to support the max gas amount specified in the transaction, which ensures that the transaction can pay for the resources it uses.
Execution → VM (VM.3)
The execution component utilizes the VM to execute a transaction via VM::ExecuteTransaction()
.
It is important to understand that executing a transaction is different from updating the state of the ledger and persisting the results in storage. A transaction TN is first executed as part of an attempt to reach agreement on blocks during consensus. If agreement is reached with the other validators on the ordering of transactions and their execution results, the results are persisted in storage and the state of the ledger is updated.
Mempool → VM (VM.4)
When mempool receives a transaction from other validators via shared mempool, mempool invokes VM README
For implementation details refer to the Virtual Machine README.
Mempool
Figure 1.4 Mempool
Mempool is a shared buffer that holds the transactions that are “waiting” to be executed. When a new transaction is added to the mempool, the mempool shares this transaction with other validators in the system. To reduce network consumption in the “shared mempool,” each validator is responsible for delivering its own transactions to other validators. When a validator receives a transaction from the mempool of another validator, the transaction is added to the mempool of the recipient validator.
AC → Mempool (MP.1)
- After performing initial validation checks, a validator's AC sends the transaction to the validator’s mempool.
- The mempool for validator VX accepts transaction TN for the sender's account only if the sequence number of TN is greater than or equal to the current sequence number of the sender's account.
Mempool → Other Validators (MP.2)
- The mempool of validator VX shares transaction TN with the other validators on the same network.
- Other validators share the transactions in their mempool with VX’s mempool.
Consensus → Mempool (MP.3)
- When validator VX becomes the leader, its consensus will pull a block of transactions from its mempool and replicate the block to other validators. It does this to arrive at a consensus on the ordering of transactions and the execution results of the transactions in the block.
- Note that just because a transaction TN was included in a consensus block, it does not guarantee that TN will eventually be persisted in the distributed database of the blockchain.
Mempool → VM (MP.4)
When mempool receives a transaction from other validators, mempool invokes Mempool README
For implementation details refer to the Mempool README.
Consensus
Figure 1.5 Consensus
The consensus component is responsible for ordering blocks of transactions and agreeing on the results of execution by participating in the Consensus → Mempool (CO.1)
When validator VX is a leader/proposer, the consensus of VX pulls a block of transactions from its mempool via: Mempool::GetBlock()
, and forms a proposal.
Consensus → Other Validators (CO.2)
If VX is a proposer/leader, its consensus replicates the proposed block of transactions to other validators.
Consensus → Execution, Consensus → Other Validators (CO.3)
- To execute a block of transactions, consensus interacts with the execution component. Consensus executes a block of transactions via
Execution:ExecuteBlock()
(Refer to Consensus → Execution (CO.4)If enough validators vote for the same execution result, the consensus component of VX informs execution via
Execution::CommitBlock()
that this block is ready to be committed.Consensus README
For implementation details refer to the Consensus README.
Execution
Figure 1.6 Execution
Execution's job is to coordinate the execution of a block of transactions and maintain a transient state that can be voted upon by consensus.
Consensus → Execution (EX.1)
- Consensus requests execution to execute a block of transactions via:
Execution::ExecuteBlock()
. - Execution maintains a “scratchpad,” which holds in-memory copies of the relevant portions of the Execution → VM (EX.2)
When consensus requests execution to execute a block of transactions via
Execution::ExecuteBlock()
, execution uses the VM to determine the results of executing the block of transactions.Consensus → Execution (EX.3)
If a quorum of validators agrees on the block execution results, consensus of each validator informs its execution component via
Execution::CommitBlock()
that this block is ready to be committed. This call to the execution component will include the signatures of the agreeing validators to provide proof of their agreement.Execution → Storage (EX.4)
Execution takes the values from its “scratchpad” and sends them to storage for persistence via
Storage::SaveTransactions()
. Execution then prunes the old values from the “scratchpad” that are no longer needed (for example, parallel blocks that cannot be committed).Execution README
For implementation details refer to the Execution README.
Storage
Figure 1.7 Storage
The storage component persists agreed upon blocks of transactions and their execution results. A block/set of transactions (which includes transaction TN) will be saved via storage when:
- There is agreement between more than 2f+1 of the validators participating in consensus on all of the following:
- The transactions to include in a block.
- The order of the transactions.
- The execution results of the transactions to be included in the block.
Refer to Merkle accumulators for information on how a transaction is appended to the data structure representing the blockchain.
VM → Storage (ST.1)
When AC or mempool invoke
VM::ValidateTransaction()
to validate a transaction,VM::ValidateTransaction()
loads the sender's account from storage and performs the read-only validity checks on the transaction.Execution → Storage (ST.2)
When consensus calls
Execution::ExecuteBlock()
, execution reads the current state from storage combined with the in-memory “scratchpad” data to determine the execution results.Execution → Storage (ST.3)
- Once consensus is reached on a block of transactions, execution calls storage via
Storage::SaveTransactions()
to save the block of transactions and permanently record them. This will also store the signatures from the validator nodes who agreed on this block of transactions. - The in-memory data in “scratchpad” for this block is passed to updated storage and persist the transactions.
- When the storage is updated, the sequence numbers of all resources modified by each transaction are updated accordingly.
- Note: The sequence number of an account on the Libra Blockchain increments by one for each committed transaction originating from that account.
AC → Storage (ST.4)
For client queries that read information from the blockchain, AC directly interacts with storage to read the requested information.
Storage README
For implementation details refer to the Storage README.
Reference
- Welcome page.
- Libra Protocol: Key Concepts — Introduces you to the fundamental concepts of the Libra protocol.
- My First Transaction — Guides you through executing your very first transaction on the Libra Blockchain using the Libra CLI client.
- Getting Started With Move — Introduces you to a new blockchain programming language called Move.
- Libra Core Overview — Provides the concept and implementation details of the Libra Core components through READMEs.
- CLI Guide — Lists the commands (and their usage) of the Libra CLI client.
- Libra Glossary — Provides a quick reference to Libra terminology.
- State Machine Replication in the Libra Blockchain — Provides a detailed look into our consensus protocol LibraBFT.
- There is agreement between more than 2f+1 of the validators participating in consensus on all of the following:
- Consensus requests execution to execute a block of transactions via: