Back to Blog

Sichern Sie das Solana-Ökosystem (2) — Aufrufe zwischen Programmen

March 18, 2022
6 min read

0. Rückblick

1. Übersicht

Im vorherigen Blog haben wir die Bereitstellung und Interaktion mit Programmen vorgestellt. Neben dem Aufruf von Anweisungen eines Programms von der Client-Seite aus ermöglicht Solana Programmen auch, sich über einen Mechanismus namens Cross-Program Invocation gegenseitig aufzurufen. In diesem Beitrag erläutern wir die Verwendung von Cross-Program Invocation. Der Testcode ist hier.

2. Cross Program Invocation

Cross Program Invocation wird üblicherweise mit der Funktion invoke implementiert. In diesem Abschnitt illustrieren wir die Verwendung von invoke beim Übertragen von Lamports innerhalb eines Programms.

In Solana gibt es ein natives Programm namens System Program, das eine Rolle bei der Erstellung neuer Konten und der Übertragung von Lamports (SOL) spielt. In diesem Fall ruft Programm A beim Übertragen von Lamports innerhalb eines Programms die Funktion transfer() im System Program auf. Lassen Sie uns das konkrete Beispiel unten durchgehen.

2.1 Code-Überprüfung

Zeile 3 bis 10 importieren die erforderlichen Bibliotheken. Beachten Sie, dass sich die Funktion invoke() in der Bibliothek solana_program::program befindet.

In der Funktion process_instruction extrahieren die Zeilen 22 bis 30 die drei vom Client übergebenen Konten. Beachten Sie, dass die Lamports von from_account an to_account übertragen werden. Von Zeile 33 bis 44 wird die Funktion invoke() aufgerufen. Sie empfängt zwei Argumente. Das erste ist die aufgerufene Zielanweisung und das zweite ist eine Menge von Konten. In diesem Beispiel ist die Zielanweisung transfer(), die zur Übertragung von Lamports verwendet wird. Die Konten umfassen alle von der aufgerufenen Anweisung benötigten Konten. In diesem Fall from_account und to_account.

Das bereitgestellte Programm finden Sie unter folgendem Link.

https://explorer.solana.com/address/EPaLuYQ4c11BJAe9ucLbta3xGFb17Zy3cZh3UDPbXRG9?cluster=devnet

2.2 Übertragung der Lamports

Wie erwähnt, senden wir die Transaktion an das bereitgestellte Programm. Das bereitgestellte Programm ruft dann das System Program auf, um die Lamports an die Zieladresse zu übertragen. Der obige Code zeigt, wie der Client die Transaktionen erstellt. Die Zeilen 93 bis 101 extrahieren die Program-ID des bereitgestellten Programms. Die Zeilen 103 bis 109 generieren die Adressen des Absenders, Empfängers und des System Program. Die Zeilen 111 bis 117 konstruieren die Transaktion. Zeile 118, die Transaktion wird an den Solana-Cluster gesendet. Beachten Sie, dass der einzige Unterzeichner dieser Transaktion der Absender ist, der in Zeile 112 festgelegt ist. Der Absender muss die Transaktion autorisieren (d. h. unterzeichnen), die Geld von seinem Konto abbucht, und der Empfänger muss dies nicht tun (Zeile 113).

Die Transaktion finden Sie unter folgendem Link.

https://explorer.solana.com/tx/4cxqnff8SakVcE9y5phmh6utcbBUGaLDPvqMRgSy9aPGdNVH6DCsQyJXCCzRGvW5CpygUi5pqhgBQxczXnWCoqPJ?cluster=devnet

3. Invoke oder Invoke_signed

In Solana können Programme zur Laufzeit Konten generieren, die als Program Derived Addresses (PDA) bezeichnet werden. Wenn die von einem Programm aufgerufene Zielanweisung signierte Konten mit PDA enthält, sollte invoke_signed() anstelle von invoke() verwendet werden. Wir verwenden ein weiteres Beispiel, um die Verwendung von invoke_signed() zu demonstrieren. Lassen Sie uns zunächst den Vertragscode durchgehen.

3.1 Code-Überprüfung

In diesem Beispiel erstellen wir zur Laufzeit eine PDA innerhalb eines Programms (d. h. Programm B). Um eine PDA zu erstellen, muss das System Program in Programm B aufgerufen werden.

Zeile 3 bis 10 importieren die erforderlichen Bibliotheken. Beachten Sie, dass invoke_signed() diesmal importiert wird (Zeile 6).

Ähnlich wie im Beispiel in Abschnitt 2 extrahieren wir die erforderlichen Konten (Zeile 22 - Zeile 27), nämlich System Program und PDA. Anschließend verwenden wir die Funktion find_program_address(), um die Adresse der PDA und den Seed zu generieren, der verwendet wird, um diese PDA von der ed25519-Kurve zu verschieben (Zeile 29 - Zeile 30). Dies soll sicherstellen, dass die Adresse keinen zugehörigen privaten Schlüssel hat. In diesem Beispiel verwenden der Client und das Programm denselben Seed (d. h. 'You pass butter'), um die PDA zu generieren. Somit sollte der öffentliche Schlüssel derselbe sein, was von Zeile 31 bis 34 geprüft wird. Danach rufen wir invoke_signer auf, um die Anweisung allocate() von Zeile 37 bis 47 auszugeben. Im Gegensatz zur Funktion invoke() nimmt sie ein weiteres Argument entgegen, nämlich die Seeds, die zur Erstellung der PDA verwendet wurden, sowie den Bump-Seed, der von der Funktion find_program_address() verwendet wird.

Um ein Konto zu erstellen/zuzuweisen, muss das Konto selbst eine Signatur bereitstellen, und in diesem Beispiel ist die PDA der Unterzeichner. Um die PDA zu signieren, wird invoke_signed verwendet. Insbesondere verwendet Solana die Seeds und die programId des Aufrufers (d. h. Programm B), um die PDA neu zu erstellen und sie mit den angegebenen Konten (dem zweiten Argument) abzugleichen. Wenn sie gleich sind, wird die PDA signiert.

Das bereitgestellte Programm kann unten eingesehen werden.

https://explorer.solana.com/address/4h3RXGsouTRvUWNG1Dqq2tuuASTXFebHC3wFzv3tSFCK?cluster=devnet

3.2 Erstellen einer PDA

Lassen Sie uns das Client-Skript für das zweite Beispiel durchgehen.

In Zeile 104 extrahieren wir die PDA und den Bump-Seed über die Funktion findProgramAddress(). Von Zeile 112 bis Zeile 120 wird die Transaktion erstellt und gesendet. Beachten Sie, dass die Eigenschaft (isSigner) der PDA hier 'false' ist (Zeile 113), da sie nicht vom Client signiert werden kann. Zur Laufzeit signiert Programm B die PDA und ruft die allocate-Anweisung im Programm System Program auf.

Sie finden die zugewiesene PDA in der folgenden Transaktion.

https://explorer.solana.com/tx/5fzdfzbD4281pY1HJm37f1fxSEMGmWtQmbmFPzEiP9v6hWF8GRRZmfcMDvPJugTrs3npnCsaWUGvw15URyBhx3LS?cluster=devnet

3.3 Können wir Invoke() verwenden?

Um zu demonstrieren, dass invoke hier nicht verwendet werden kann, verwenden wir ein anderes Programm (d. h. Programm C), um die allocation-Anweisung aufzurufen.

Die einzige Änderung, die wir vorgenommen haben, ist die Umwandlung der Funktion invoke_signed() in die Funktion invoke(). Wir haben festgestellt, dass das Konto nicht erstellt werden konnte.

Der Fehler zeigt, dass die Cross-Program Invocation einen Unterzeichner benötigt, um erfolgreich ausgeführt zu werden. Das heißt, die Funktion invoke_signed() ist erforderlich.

4. Schlussfolgerung

In diesem Artikel haben wir vorgestellt, wie die Cross-Program Invocation über die Funktion invoke() implementiert wird. Wir haben auch verschiedene Beispiele verwendet, um die Unterschiede zwischen invoke() und invoke_signed() zu veranschaulichen. Bleiben Sie dran, weitere Artikel dieser Reihe werden veröffentlicht.

Lesen Sie andere Artikel dieser Reihe:

Sign up for the latest updates
~$15.9M Lost: Trusted Volumes & More | BlockSec Weekly
Security Insights

~$15.9M Lost: Trusted Volumes & More | BlockSec Weekly

This BlockSec bi-weekly security report covers 11 notable attack incidents identified between April 27 and May 10, 2026, across Sui, Ethereum, BNB Chain, Base, Blast, and Berachain, with total estimated losses of approximately $15.9M. Three incidents are analyzed in detail: the highlighted $1.14M Aftermath Finance exploit on Sui, where a signed/unsigned semantic mismatch in the builder-fee validation allowed an attacker to inject a negative fee that was converted into positive collateral during settlement; the $5.87M Trusted Volumes RFQ authorization mismatch on Ethereum; and the $5.7M Wasabi Protocol infrastructure-to-contract-control compromise across multiple EVM chains.

Newsletter - April 2026
Security Insights

Newsletter - April 2026

In April 2026, the DeFi ecosystem experienced three major security incidents. KelpDAO lost ~$290M due to an insecure 1-of-1 DVN bridge configuration exploited via RPC infrastructure compromise, Drift Protocol suffered ~$285M from a multisig governance takeover leveraging Solana's durable nonce mechanism, and Rhea Finance incurred ~$18.4M following a business logic flaw in its margin-trading module that allowed circular swap path manipulatio

~$7.04M Lost: GiddyDefi, Volo Vault & More | BlockSec Weekly
Security Insights

~$7.04M Lost: GiddyDefi, Volo Vault & More | BlockSec Weekly

This BlockSec weekly security report covers eight attack incidents detected between April 20 and April 26, 2026, across Ethereum, Avalanche, Sui, Base, HyperLiquid, and MegaETH, with total estimated losses of approximately $7.04M. The highlighted incident is the $1.3M GiddyDefi exploit, where the attacker did not break any cryptography or use a flash loan but simply replayed an existing on-chain EIP-712 signature with the unsigned `aggregator` and `fromToken` fields swapped out for a malicious contract, demonstrating how partial signature coverage turns any historical signature into a generic permit. Other incidents include a $3.5M Volo Vault operator key compromise on Sui, a $1.5M Purrlend privileged-role takeover, a $413K SingularityFinance oracle misconfiguration, a $142.7K Scallop cross-pool index injection, a $72.35K Kipseli Router decimal mismatch, a $50.7K REVLoans (Juicebox) accounting pollution, and a $64K Custom Rebalancer arbitrary-call exploit.