Simplifying Libra transaction payloads: Deprecation of the “Program” type

October 22, 2019
Novi Engineering

Overview

We are simplifying the types of payload a Libra* transaction can contain. Currently, the transaction payload of type “Program” allows both a Move module to be published and a Move transaction script to be executed within the same transaction. We will soon be deprecating the “Program” type. The benefits of making this change and the impact of this change are described in this document.

Payload of a Libra transaction

Currently, the payload of a Libra transaction has the following three variants:

pub enumTransactionPayload {
    /// A regular programmatic transaction that is executed by the VM.
    Program(Program),     /// A genesis transaction.
    WriteSet(WriteSet),
    /// A transaction that publishes a module.
    Module(Module),
    /// A transaction that executes a script.
    Script(Script),
}
  • Program
    • Encodes a peer-to-peer transaction.
    • Within the same transaction, Move modules can be published and Move transaction scripts can be executed.
  • Writeset
    • Contains a simple writeset.
    • Used for genesis transactions only.
  • Module
    • Used to publish a Move module.
    • The payload is a single serialized Move CompiledModule.
    • A transaction with this type of payload just publishes the CompiledModule and does nothing else.
  • Script
    • Used to execute a Move transaction script.
    • The payload is a serialized Move CompiledScript.
    • A transaction with this type of payload just executes the CompiledScript and does nothing else.

Note: Currently, module transactions are accepted on local networks only.

What will change?

You may have noticed that the “Program” type is essentially a combination of the “Module” and the “Script” types. In the next week, the “Program” type will be removed from this implementation.

What are the benefits of this change?

There are two major benefits to using “Script” and “Module” types separately instead of combining them into the (soon-to-be deprecated) “Program” type:

  • Reduces the size of a transaction – In the current implementation, for a regular peer-to-peer transaction, the module information should be encoded in the transaction as an empty “to-be-published” modules vector, even if there is no module to be published. This costs extra bytes.
  • Simplifies the VM structure – The VM caches the modules published on-chain for better performance. The semantics for transactions of payload type “Program” complicates the caching story of VM significantly. The VM must deal with the fact that, even if a “Program” attempts to publish a legitimate module, it can fail subsequently during the execution of the transaction script. When there’s a script execution failure, the VM needs to get rid of the cached module so that this specific module is not visible to future transactions.

What do we lose from this change?

Nothing!

Move modules are stateless, and there’s no difference between publishing modules within one transaction or across different transactions.

How do we transition to the new implementation?

The Libra codebase has been modified and all occurrences of the old transaction type have been removed (PR #923).

If you want to execute a transaction with a “Script” payload, the current transaction payload would look like this:

TransactionPayload::Program(
Program::new(
/*code*/ some_bytes,
/*args*/ args_vector,
/*module*/ vec![])
)

You will need to change it to:

TransactionPayload::Script(
Script::new(
/*code*/ some_bytes,
/*args*/ args_vector)
)

Similarly, if you were trying to publish a module, your current transaction payload would look like this:

TransactionPayload::Program(
Program::new(
/*code*/ some_bytes,    // Just an empty main function
/*args*/ args_vector,
/*module*/ vec![compiled_module_bytes])
)

You will need to change it to:

TransactionPayload::Module(Module::new(/*code*/ compiled_module_bytes))

We will support all transaction payload types on testnet for a few more weeks, following which the “Program” variant in transaction.rs will be removed.

Who is impacted by this change?

As the transaction payload bytes remain unchanged, this transition will be easy. However, wallet and client developers should be aware of this transition, as this will change the format of the transaction accepted by the Libra testnet.

Libra developer documentation updated

The Libra developer documentation has been updated to reflect these new changes. Assume that any Libra transaction contains a script payload.

*On December 1, 2020, the Libra Association was renamed to Diem Association.