Versioned Transactions - v0: Address Lookup Tables | Solana Validator

web3.js - Transaction v2 vs v1 - Solana Stack Exchange

versioned tx 和 legacy tx的区别是什么?

<aside> 💡 versioned tx 是为了支持 Address Lookup Table Account (ALT)特性的最新版本的tx格式

</aside>

从tx格式上做了修改,用来判断tx 的版本

Messages transmitted to Solana validators must not exceed the IPv6 MTU size to ensure fast and reliable network transmission of cluster info over UDP. Solana's networking stack uses a conservative MTU size of 1280 bytes which, after accounting for headers, leaves 1232 bytes for packet data like serialized transactions. (header 48 bytes)

Therefore the current cap is about 35 accounts after accounting for signatures and other transaction metadata.

Proposed Solution

  1. Introduce a new program which manages on-chain address lookup tables
  2. Add a new transaction format which can make use of on-chain address lookup tables to efficiently load more accounts in a single transaction.

After addresses are stored on-chain in an address lookup table account, they may be succinctly referenced in a transaction using a 1-byte u8 index rather than a full 32-byte address. This will require a new transaction format to make use of these succinct references as well as runtime handling for looking up and loading addresses from the on-chain lookup tables.

Newly appended addresses require one slot to warmup before being available to transactions for lookups.

Since transactions use a u8 index to look up addresses, address tables can store up to 256 addresses each. In addition to stored addresses, address table accounts also tracks various metadata explained below.

Versioned Transactions

In order to support address table lookups, the structure of serialized transactions must be modified. The new transaction format should not affect transaction processing in the Solana program runtime beyond the increased capacity for accounts and program invocations. Invoked programs will be unaware of which transaction format was used.

The new transaction format must be distinguished from the current transaction format. Current transactions can fit at most 19 signatures (64-bytes each) but the message header encodes num_required_signatures as a u8. Since the upper bit of the u8 will never be set for a valid transaction, we can enable it to denote whether a transaction should be decoded with the versioned format or not.

The original transaction format will be referred to as the legacy transaction version and the first versioned transaction format will start at version 0.

New Transaction Format

#[derive(Serialize, Deserialize)]
pub struct VersionedTransaction {
    /// List of signatures
    #[serde(with = "short_vec")]
    pub signatures: Vec<Signature>,
    /// Message to sign.
    pub message: VersionedMessage,
}

// Uses custom serialization. If the first bit is set, the remaining bits
// in the first byte will encode a version number. If the first bit is not
// set, the first byte will be treated as the first byte of an encoded
// legacy message.
pub enum VersionedMessage {
    Legacy(LegacyMessage),
    V0(v0::Message),
}

// The structure of the new v0 Message
#[derive(Serialize, Deserialize)]
pub struct Message {
  // unchanged
  pub header: MessageHeader,

  // unchanged
  #[serde(with = "short_vec")]
  pub account_keys: Vec<Pubkey>,

  // unchanged
  pub recent_blockhash: Hash,

  // unchanged
  //
  // # Notes
  //
  // Account and program indexes will index into the list of addresses
  // constructed from the concatenation of three key lists:
  //   1) message `account_keys`
  //   2) ordered list of keys loaded from address table `writable_indexes`
  //   3) ordered list of keys loaded from address table `readonly_indexes`
  #[serde(with = "short_vec")]
  pub instructions: Vec<CompiledInstruction>,

  /// List of address table lookups used to load additional accounts
  /// for this transaction.
  #[serde(with = "short_vec")]
  pub address_table_lookups: Vec<MessageAddressTableLookup>,
}

/// Address table lookups describe an on-chain address lookup table to use
/// for loading more readonly and writable accounts in a single tx.
#[derive(Serialize, Deserialize)]
pub struct MessageAddressTableLookup {
  /// Address lookup table account key
  pub account_key: Pubkey,
  /// List of indexes used to load writable account addresses
  #[serde(with = "short_vec")]
  pub writable_indexes: Vec<u8>,
  /// List of indexes used to load readonly account addresses
  #[serde(with = "short_vec")]
  pub readonly_indexes: Vec<u8>,
}