Συναλλαγές
Για να αλληλεπιδράσετε με το δίκτυο Solana, πρέπει να στείλετε μια συναλλαγή. Μπορείτε να σκεφτείτε μια συναλλαγή ως έναν φάκελο που περιέχει αρκετές φόρμες. Κάθε φόρμα είναι μια οδηγία που λέει στο δίκτυο τι να κάνει. Η αποστολή της συναλλαγής είναι σαν να ταχυδρομείτε τον φάκελο ώστε να μπορούν να επεξεργαστούν οι φόρμες.
Το παρακάτω παράδειγμα δείχνει μια απλοποιημένη έκδοση δύο συναλλαγών. Όταν η πρώτη συναλλαγή επεξεργαστεί, θα εκτελέσει μια μόνο οδηγία. Όταν η δεύτερη συναλλαγή επεξεργαστεί, θα εκτελέσει τρεις οδηγίες με διαδοχική σειρά: πρώτα την οδηγία 1, ακολουθούμενη από την οδηγία 2, ακολουθούμενη από την οδηγία 3.
Οι συναλλαγές είναι ατομικές: Αν μια μόνο οδηγία αποτύχει, ολόκληρη η συναλλαγή θα αποτύχει και δεν θα πραγματοποιηθούν αλλαγές.
Ένα απλοποιημένο διάγραμμα που δείχνει δύο συναλλαγές
Μια
Transaction
αποτελείται από τις ακόλουθες πληροφορίες:
signatures: Ένας πίνακας από υπογραφέςmessage: Πληροφορίες συναλλαγής, συμπεριλαμβανομένης της λίστας οδηγιών προς επεξεργασία
pub struct Transaction {#[wasm_bindgen(skip)]#[serde(with = "short_vec")]pub signatures: Vec<Signature>,#[wasm_bindgen(skip)]pub message: Message,}
Διάγραμμα που δείχνει τα δύο μέρη μιας συναλλαγής
Οι συναλλαγές έχουν συνολικό όριο μεγέθους
1232
bytes. Αυτό το όριο περιλαμβάνει τόσο τον πίνακα signatures όσο
και τη δομή message.
Αυτό το όριο προέρχεται από το μέγεθος της Μέγιστης Μονάδας Μετάδοσης (MTU) του IPv6 που είναι 1280 bytes, μείον 48 bytes για τις επικεφαλίδες δικτύου (40 bytes IPv6 + 8 bytes επικεφαλίδα).
Διάγραμμα που δείχνει τη μορφή συναλλαγής και τα όρια μεγέθους
Υπογραφές
Ο πίνακας signatures της συναλλαγής περιέχει δομές Signature. Κάθε
Signature
είναι 64 bytes και δημιουργείται με την υπογραφή του Message της συναλλαγής με
το ιδιωτικό κλειδί του λογαριασμού. Μια υπογραφή πρέπει να παρέχεται για κάθε
λογαριασμό υπογράφοντα που περιλαμβάνεται σε οποιαδήποτε
από τις οδηγίες της συναλλαγής.
Η πρώτη υπογραφή ανήκει στον λογαριασμό που θα πληρώσει το βασικό τέλος της συναλλαγής και αποτελεί την υπογραφή της συναλλαγής. Η υπογραφή της συναλλαγής μπορεί να χρησιμοποιηθεί για την αναζήτηση των λεπτομερειών της συναλλαγής στο δίκτυο.
Μήνυμα
Το message της συναλλαγής είναι μια δομή
Message
που περιέχει τις ακόλουθες πληροφορίες:
header: Η κεφαλίδα του μηνύματοςaccount_keys: Ένας πίνακας διευθύνσεων λογαριασμών που απαιτούνται από τις οδηγίες της συναλλαγήςrecent_blockhash: Ένα blockhash που λειτουργεί ως χρονική σήμανση για τη συναλλαγήinstructions: Ένας πίνακας οδηγιών
Για εξοικονόμηση χώρου, η συναλλαγή δεν αποθηκεύει τα δικαιώματα για κάθε
λογαριασμό ξεχωριστά. Αντίθετα, τα δικαιώματα λογαριασμών καθορίζονται
χρησιμοποιώντας το header και το account_keys.
pub struct Message {/// The message header, identifying signed and read-only `account_keys`.pub header: MessageHeader,/// All the account keys used by this transaction.#[serde(with = "short_vec")]pub account_keys: Vec<Pubkey>,/// The id of a recent ledger entry.pub recent_blockhash: Hash,/// Programs that will be executed in sequence and committed in/// one atomic transaction if all succeed.#[serde(with = "short_vec")]pub instructions: Vec<CompiledInstruction>,}
Κεφαλίδα
Το header του μηνύματος είναι μια δομή
MessageHeader.
Περιέχει τις ακόλουθες πληροφορίες:
num_required_signatures: Ο συνολικός αριθμός υπογραφών που απαιτούνται από τη συναλλαγήnum_readonly_signed_accounts: Ο συνολικός αριθμός λογαριασμών μόνο για ανάγνωση που απαιτούν υπογραφέςnum_readonly_unsigned_accounts: Ο συνολικός αριθμός λογαριασμών μόνο για ανάγνωση που δεν απαιτούν υπογραφές
pub struct MessageHeader {/// The number of signatures required for this message to be considered/// valid. The signers of those signatures must match the first/// `num_required_signatures` of [`Message::account_keys`].pub num_required_signatures: u8,/// The last `num_readonly_signed_accounts` of the signed keys are read-only/// accounts.pub num_readonly_signed_accounts: u8,/// The last `num_readonly_unsigned_accounts` of the unsigned keys are/// read-only accounts.pub num_readonly_unsigned_accounts: u8,}
Διάγραμμα που δείχνει τα τρία μέρη της κεφαλίδας μηνύματος
Διευθύνσεις λογαριασμών
Το
account_keys
του μηνύματος είναι ένας πίνακας διευθύνσεων λογαριασμών, που αποστέλλεται σε
συμπαγή μορφή πίνακα. Το
πρόθεμα του πίνακα υποδεικνύει το μήκος του. Κάθε στοιχείο στον πίνακα είναι ένα
δημόσιο κλειδί, που δείχνει σε έναν λογαριασμό που χρησιμοποιείται από τις
οδηγίες του. Ο πίνακας accounts_keys πρέπει να είναι πλήρης και αυστηρά
ταξινομημένος, ως εξής:
- Υπογράφων + Εγγράψιμος
- Υπογράφων + Μόνο για ανάγνωση
- Μη υπογράφων + Εγγράψιμος
- Μη υπογράφων + Μόνο για ανάγνωση
Η αυστηρή ταξινόμηση επιτρέπει στον πίνακα account_keys να συνδυαστεί με τις
πληροφορίες στο header του μηνύματος για τον καθορισμό των
δικαιωμάτων για κάθε λογαριασμό.
Διάγραμμα που δείχνει τη σειρά του πίνακα διευθύνσεων λογαριασμών
Πρόσφατο blockhash
Το recent_blockhash του μηνύματος είναι μια τιμή κατακερματισμού που
λειτουργεί ως χρονική σήμανση της συναλλαγής και αποτρέπει τις διπλές
συναλλαγές. Ένα blockhash λήγει μετά από
150 μπλοκ.
(Ισοδύναμο με ένα λεπτό—υποθέτοντας ότι κάθε μπλοκ είναι 400ms.) Μετά τη λήξη
του μπλοκ, η συναλλαγή λήγει και δεν μπορεί να επεξεργαστεί.
Η μέθοδος RPC getLatestBlockhash σας
επιτρέπει να λάβετε το τρέχον blockhash και το τελευταίο ύψος μπλοκ στο οποίο
το blockhash θα είναι έγκυρο.
Οδηγίες
Το
instructions
του μηνύματος είναι ένας πίνακας όλων των οδηγιών που πρόκειται να
επεξεργαστούν, αποστέλλεται σε
συμπαγή μορφή πίνακα. Το
πρόθεμα του πίνακα υποδεικνύει το μήκος του. Κάθε στοιχείο στον πίνακα είναι μια
δομή
CompiledInstruction
και περιλαμβάνει τις ακόλουθες πληροφορίες:
program_id_index: Ένας δείκτης που δείχνει σε μια διεύθυνση στον πίνακαaccount_keys. Αυτή η τιμή υποδεικνύει τη διεύθυνση του προγράμματος που επεξεργάζεται την οδηγία.accounts: Ένας πίνακας δεικτών που δείχνουν σε διευθύνσεις στον πίνακαaccount_keys. Κάθε δείκτης δείχνει στη διεύθυνση ενός λογαριασμού που απαιτείται για αυτήν την οδηγία.data: Ένας πίνακας byte που καθορίζει ποια οδηγία θα επικαλεστεί στο πρόγραμμα. Περιλαμβάνει επίσης τυχόν πρόσθετα δεδομένα που απαιτούνται από την οδηγία. (Για παράδειγμα, ορίσματα συνάρτησης)
pub struct CompiledInstruction {/// Index into the transaction keys array indicating the program account that executes this instruction.pub program_id_index: u8,/// Ordered indices into the transaction keys array indicating which accounts to pass to the program.#[serde(with = "short_vec")]pub accounts: Vec<u8>,/// The program input data.#[serde(with = "short_vec")]pub data: Vec<u8>,}
Συμπαγής πίνακας οδηγιών
Παράδειγμα δομής συναλλαγής
Το ακόλουθο παράδειγμα δείχνει τη δομή μιας συναλλαγής που περιέχει μια μόνο οδηγία μεταφοράς SOL.
import {createSolanaRpc,generateKeyPairSigner,lamports,createTransactionMessage,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,appendTransactionMessageInstructions,pipe,signTransactionMessageWithSigners,getCompiledTransactionMessageDecoder} from "@solana/kit";import { getTransferSolInstruction } from "@solana-program/system";const rpc = createSolanaRpc("http://localhost:8899");const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();// Generate sender and recipient keypairsconst sender = await generateKeyPairSigner();const recipient = await generateKeyPairSigner();// Define the amount to transferconst LAMPORTS_PER_SOL = 1_000_000_000n;const transferAmount = lamports(LAMPORTS_PER_SOL / 100n); // 0.01 SOL// Create a transfer instruction for transferring SOL from sender to recipientconst transferInstruction = getTransferSolInstruction({source: sender,destination: recipient.address,amount: transferAmount});// Create transaction messageconst transactionMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(sender, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),(tx) => appendTransactionMessageInstructions([transferInstruction], tx));const signedTransaction =await signTransactionMessageWithSigners(transactionMessage);// Decode the messageBytesconst compiledTransactionMessage =getCompiledTransactionMessageDecoder().decode(signedTransaction.messageBytes);console.log(JSON.stringify(compiledTransactionMessage, null, 2));
Ο παρακάτω κώδικας δείχνει την έξοδο από τα προηγούμενα αποσπάσματα κώδικα. Η μορφή διαφέρει μεταξύ των SDK, αλλά παρατηρήστε ότι κάθε οδηγία περιέχει τις ίδιες απαιτούμενες πληροφορίες.
{"version": 0,"header": {"numSignerAccounts": 1,"numReadonlySignerAccounts": 0,"numReadonlyNonSignerAccounts": 1},"staticAccounts": ["HoCy8p5xxDDYTYWEbQZasEjVNM5rxvidx8AfyqA4ywBa","5T388jBjovy7d8mQ3emHxMDTbUF8b7nWvAnSiP3EAdFL","11111111111111111111111111111111"],"lifetimeToken": "EGCWPUEXhqHJWYBfDirq3mHZb4qDpATmYqBZMBy9TBC1","instructions": [{"programAddressIndex": 2,"accountIndices": [0, 1],"data": {"0": 2,"1": 0,"2": 0,"3": 0,"4": 128,"5": 150,"6": 152,"7": 0,"8": 0,"9": 0,"10": 0,"11": 0}}]}
Μετά την υποβολή μιας συναλλαγής, μπορείτε να ανακτήσετε τις λεπτομέρειές της χρησιμοποιώντας την υπογραφή της συναλλαγής και τη μέθοδο RPC getTransaction. Η απάντηση θα έχει μια δομή παρόμοια με το ακόλουθο απόσπασμα.
Μπορείτε επίσης να βρείτε τη συναλλαγή χρησιμοποιώντας τον Solana Explorer.
{"blockTime": 1745196488,"meta": {"computeUnitsConsumed": 150,"err": null,"fee": 5000,"innerInstructions": [],"loadedAddresses": {"readonly": [],"writable": []},"logMessages": ["Program 11111111111111111111111111111111 invoke [1]","Program 11111111111111111111111111111111 success"],"postBalances": [989995000, 10000000, 1],"postTokenBalances": [],"preBalances": [1000000000, 0, 1],"preTokenBalances": [],"rewards": [],"status": {"Ok": null}},"slot": 13049,"transaction": {"message": {"header": {"numReadonlySignedAccounts": 0,"numReadonlyUnsignedAccounts": 1,"numRequiredSignatures": 1},"accountKeys": ["8PLdpLxkuv9Nt8w3XcGXvNa663LXDjSrSNon4EK7QSjQ","7GLg7bqgLBv1HVWXKgWAm6YoPf1LoWnyWGABbgk487Ma","11111111111111111111111111111111"],"recentBlockhash": "7ZCxc2SDhzV2bYgEQqdxTpweYJkpwshVSDtXuY7uPtjf","instructions": [{"accounts": [0, 1],"data": "3Bxs4NN8M2Yn4TLb","programIdIndex": 2,"stackHeight": null}],"indexToProgramIds": {}},"signatures": ["3jUKrQp1UGq5ih6FTDUUt2kkqUfoG2o4kY5T1DoVHK2tXXDLdxJSXzuJGY4JPoRivgbi45U2bc7LZfMa6C4R3szX"]},"version": "legacy"}
Is this page helpful?