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:
-
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 mitTransactionError::InvalidAccountForFeefehl. -
Limit für geladene Datengröße: Die Gesamtgröße aller geladenen Konten (einschließlich eines
TRANSACTION_ACCOUNT_BASE_SIZEvon 64 Bytes pro Konto) darfMAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES(64 MiB) nicht überschreiten. Das Überschreiten dieses Limits erzeugtTransactionError::MaxLoadedAccountsDataSizeExceeded. -
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 mitTransactionError::ProgramAccountNotFoundfehl. Wenn es existiert, aber einen ungültigen Besitzer hat, schlägt die Transaktion mitTransactionError::InvalidProgramForExecutionfehl. -
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_epochgesetzt aufu64::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:
| Offset | Größe | Feld | Typ |
|---|---|---|---|
| 0 | 1 | Duplikat-Markierung | u8 (0xFF = eindeutig, Index = Duplikat dieses Kontos) |
| 1 | 1 | is_signer | u8 (0 oder 1) |
| 2 | 1 | is_writable | u8 (0 oder 1) |
| 3 | 1 | executable | u8 (0 oder 1) |
| 4 | 4 | original_data_len (reserviert, immer 0) | [0u8; 4] |
| 8 | 32 | key | Pubkey |
| 40 | 32 | owner | Pubkey |
| 72 | 8 | lamports | u64 (Little-Endian) |
| 80 | 8 | data_len | u64 (Little-Endian) |
| 88 | data_len | data | [u8] |
| 88 + data_len | 10240 + Padding | Realloc-Speicherplatz + Ausrichtung | Mit Nullen gefüllt auf MAX_PERMITTED_DATA_INCREASE (10 KiB) + Padding zur Ausrichtung auf BPF_ALIGN_OF_U128 (8 Bytes) |
| ... | 8 | rent_epoch | u64 (Little-Endian) |
Nach allen Konten fügt der Puffer Folgendes hinzu:
| Größe | Feld |
|---|---|
| 8 | instruction_data_len (u64, Little-Endian) |
| instruction_data_len | instruction_data |
| 32 | program_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
Nonezurück). - Andernfalls gibt es
Some(first_index)zurück, wobeifirst_indexder 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?