Konto-Laufzeitumgebung

Zusammenfassung

Vor der Ausführung lädt die Laufzeitumgebung Konten, validiert den Fee-Zahler, prüft die Miete-Befreiung und serialisiert Kontodaten in ein Speicherlayout, auf das Programme zugreifen können.

Diese Seite behandelt Laufzeitumgebungs-Interna. Die meisten Entwickler benötigen diese Informationen nicht für die Entwicklung von Programmen. Siehe Kontostruktur für die entwicklerorientierte Ansicht.

Laden von Konten

Bevor eine Transaktion ausgeführt wird, lädt die Laufzeitumgebung alle referenzierten Konten über load_transaction_accounts(). Dieser Prozess führt mehrere Validierungen durch:

  1. Fee-Zahler-Validierung: Der Fee-Zahler (erstes Konto) muss existieren, ein Systemkonto oder Nonce-Konto sein und genügend Lamports haben, um Fees zu decken (validate_fee_payer()). Nach Zahlung der Fees muss das Konto entweder miete-befreit bleiben oder auf genau 0 Lamports gehen. Es kann nicht zwischen 0 und dem Miete-Befreiungs-Minimum enden. Nonce-Konten müssen immer genügend Lamports behalten, um miete-befreit zu bleiben. Wenn der Zahler weder ein Systemkonto noch ein Nonce-Konto ist, schlägt die Transaktion mit TransactionError::InvalidAccountForFee fehl.

  2. Limit für geladene Datengröße: Die Gesamtgröße aller geladenen Konten (einschließlich eines TRANSACTION_ACCOUNT_BASE_SIZE von 64 Bytes pro Konto) darf MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES (64 MiB) nicht überschreiten. Das Überschreiten dieses Limits erzeugt TransactionError::MaxLoadedAccountsDataSizeExceeded.

  3. Programmkonto-Validierung: Jedes Programm, das von einer Instruktion aufgerufen wird, muss existieren und im Besitz eines gültigen Loaders sein: einer der PROGRAM_OWNERS (BPF Loader Upgradeable, BPF Loader, BPF Loader Deprecated, Loader V4) oder der native Loader. Wenn das Programmkonto nicht existiert, schlägt die Transaktion mit TransactionError::ProgramAccountNotFound fehl. Wenn es existiert, aber einen ungültigen Besitzer hat, schlägt die Transaktion mit TransactionError::InvalidProgramForExecution fehl.

  4. Nicht existierende Konten: Konten, die nicht on-chain existieren, werden als Standard-Konten geladen (0 Lamports, leere Daten, im Besitz des System-Programms) mit rent_epoch gesetzt auf u64::MAX.

BPF-Serialisierungsformat

Wenn ein Programm aufgerufen wird, serialisiert die Runtime Konten in einen zusammenhängenden Speicherpuffer und übergibt ihn an die BPF-VM. Das Serialisierungsformat (für das standardmäßige ausgerichtete Format, das von allen Loadern außer dem veralteten loader-v1 verwendet wird) ist definiert in serialize_parameters_aligned().

Der Puffer beginnt mit einem u64 (8 Bytes, Little-Endian), der die Anzahl der Konten enthält. Dann enthält der Puffer für jedes Konto in der Instruktion:

OffsetGrößeFeldTyp
01Duplikat-Markierungu8 (0xFF = eindeutig, Index = Duplikat dieses Kontos)
11is_signeru8 (0 oder 1)
21is_writableu8 (0 oder 1)
31executableu8 (0 oder 1)
44original_data_len (reserviert, immer 0)[0u8; 4]
832keyPubkey
4032ownerPubkey
728lamportsu64 (Little-Endian)
808data_lenu64 (Little-Endian)
88data_lendata[u8]
88 + data_len10240 + PaddingRealloc-Speicherplatz + AusrichtungMit Nullen gefüllt auf MAX_PERMITTED_DATA_INCREASE (10 KiB) + Padding zur Ausrichtung auf BPF_ALIGN_OF_U128 (8 Bytes)
...8rent_epochu64 (Little-Endian)

Nach allen Konten fügt der Puffer Folgendes hinzu:

GrößeFeld
8instruction_data_len (u64, Little-Endian)
instruction_data_leninstruction_data
32program_id (Pubkey)

Für doppelte Konten wird nur 1 Byte (die Duplikatsmarkierung mit dem Index des Originals) plus 7 Bytes Padding geschrieben.

Kontendeduplizierung

Wenn derselbe öffentliche Kontenschlüssel mehrfach im accounts-Array einer Instruktion erscheint, dedupliziert die Runtime diese. Jeder Eintrag in der Kontenliste der Instruktion erhält seine eigene InstructionAccount-Struktur, aber Einträge, die sich auf dasselbe Konto auf Transaktionsebene beziehen, verweisen auf dieselben zugrunde liegenden Daten.

Die is_instruction_account_duplicate-Methode bestimmt, ob ein gegebener Instruktionskontenindex das erste Vorkommen oder ein Duplikat ist, indem sie den Index auf Transaktionsebene nachschlägt und den ersten Index auf Instruktionsebene findet, der darauf verweist:

  • Wenn der aktuelle Instruktionskontenindex dem ersten zugeordneten Index entspricht, ist es kein Duplikat (gibt None zurück).
  • Andernfalls gibt es Some(first_index) zurück, wobei first_index der Index des ersten Vorkommens ist.

Da alle Verweise auf dasselbe Konto dieselben zugrunde liegenden AccountSharedData teilen, sind Änderungen über einen beliebigen Verweis sofort über alle anderen Verweise sichtbar. Es kann jedoch nur eine veränderbare Ausleihe gleichzeitig gehalten werden. Der Versuch, dasselbe Konto veränderbar über zwei verschiedene Instruktionskontenindizes gleichzeitig auszuleihen, gibt InstructionError::AccountBorrowFailed zurück. Programme müssen eine Ausleihe freigeben, bevor sie eine weitere für dasselbe zugrunde liegende Konto erwerben.

Nach der Programmausführung deserialisiert die Runtime den Puffer zurück (deserialize_parameters_aligned()) und wendet alle Änderungen auf lamports, data (einschließlich Längenänderungen bis zu MAX_PERMITTED_DATA_INCREASE) und owner an.

Is this page helpful?

Inhaltsverzeichnis

Seite bearbeiten

Verwaltet von

© 2026 Solana Foundation.
Alle Rechte vorbehalten.
Verbinden Sie sich