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
The Decentralization Dilemma: Cascading Risk and Emergency Power in the KelpDAO Crisis
Security Insights

The Decentralization Dilemma: Cascading Risk and Emergency Power in the KelpDAO Crisis

This BlockSec deep-dive analyzes the KelpDAO $290M rsETH cross-chain bridge exploit (April 18, 2026), attributed to the Lazarus Group, tracing a causal chain across three layers: how a single-point DVN dependency enabled the attack, how DeFi composability cascaded the damage through Aave V3 lending markets to freeze WETH liquidity exceeding $6.7B across Ethereum, Arbitrum, Base, Mantle, and Linea, and how the crisis forced decentralized governance to exercise centralized emergency powers. The article examines three parameters that shaped the cascade's severity (LTV, pool depth, and cross-chain deployment count) and provides an exclusive technical breakdown of Arbitrum Security Council's forced state transition, an atomic contract upgrade that moved 30,766 ETH without the holder's signature.

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026

This BlockSec weekly security report covers four attack incidents detected between April 13 and April 19, 2026, across multiple chains such as Ethereum, Unichain, Arbitrum, and NEAR, with total estimated losses of approximately $310M. The highlighted incident is the $290M KelpDAO rsETH bridge exploit, where an attacker poisoned the RPC infrastructure of the sole LayerZero DVN to fabricate a cross-chain message, triggering a cascading WETH freeze across five chains and an Arbitrum Security Council forced state transition that raises questions about the actual trust boundaries of decentralized systems. Other incidents include a $242K MMR proof forgery on Hyperbridge, a $1.5M signed integer abuse on Dango, and an $18.4M circular swap path exploit on Rhea Finance's Burrowland protocol.

Weekly Web3 Security Incident Roundup | Apr 6 – Apr 12, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Apr 6 – Apr 12, 2026

This BlockSec weekly security report covers four DeFi attack incidents detected between April 6 and April 12, 2026, across Linea, BNB Chain, Arbitrum, Optimism, Avalanche, and Base, with total estimated losses of approximately $928.6K. Notable incidents include a $517K approval-related exploit where a user mistakenly approved a permissionless SquidMulticall contract enabling arbitrary external calls, a $193K business logic flaw in the HB token's reward-settlement logic that allowed direct AMM reserve manipulation, a $165.6K exploit in Denaria's perpetual DEX caused by a rounding asymmetry compounded with an unsafe cast, and a $53K access control issue in XBITVault caused by an initialization-dependent check that failed open. The report provides detailed vulnerability analysis and attack transaction breakdowns for each incident.