pub struct Message {
pub header: MessageHeader,
pub account_keys: Vec<Pubkey>,
pub recent_blockhash: Hash,
pub instructions: Vec<CompiledInstruction>,
}
Expand description
A Solana transaction message (legacy).
See the message
module documentation for further description.
Some constructors accept an optional payer
, the account responsible for
paying the cost of executing a transaction. In most cases, callers should
specify the payer explicitly in these constructors. In some cases though,
the caller is not required to specify the payer, but is still allowed to:
in the Message
structure, the first account is always the fee-payer, so if
the caller has knowledge that the first account of the constructed
transaction’s Message
is both a signer and the expected fee-payer, then
redundantly specifying the fee-payer is not strictly required.
Fields§
§header: MessageHeader
The message header, identifying signed and read-only account_keys
.
account_keys: Vec<Pubkey>
All the account keys used by this transaction.
recent_blockhash: Hash
The id of a recent ledger entry.
instructions: Vec<CompiledInstruction>
Programs that will be executed in sequence and committed in one atomic transaction if all succeed.
Implementations§
Source§impl Message
impl Message
Sourcepub fn new(instructions: &[Instruction], payer: Option<&Pubkey>) -> Self
pub fn new(instructions: &[Instruction], payer: Option<&Pubkey>) -> Self
Create a new Message
.
§Examples
This example uses the solana_sdk
, solana_rpc_client
and anyhow
crates.
use anyhow::Result;
use borsh::{BorshSerialize, BorshDeserialize};
use solana_rpc_client::rpc_client::RpcClient;
use solana_sdk::{
instruction::Instruction,
message::Message,
pubkey::Pubkey,
signature::{Keypair, Signer},
transaction::Transaction,
};
// A custom program instruction. This would typically be defined in
// another crate so it can be shared between the on-chain program and
// the client.
#[derive(BorshSerialize, BorshDeserialize)]
enum BankInstruction {
Initialize,
Deposit { lamports: u64 },
Withdraw { lamports: u64 },
}
fn send_initialize_tx(
client: &RpcClient,
program_id: Pubkey,
payer: &Keypair
) -> Result<()> {
let bank_instruction = BankInstruction::Initialize;
let instruction = Instruction::new_with_borsh(
program_id,
&bank_instruction,
vec![],
);
let message = Message::new(
&[instruction],
Some(&payer.pubkey()),
);
let blockhash = client.get_latest_blockhash()?;
let mut tx = Transaction::new(&[payer], message, blockhash);
client.send_and_confirm_transaction(&tx)?;
Ok(())
}
Sourcepub fn new_with_blockhash(
instructions: &[Instruction],
payer: Option<&Pubkey>,
blockhash: &Hash,
) -> Self
pub fn new_with_blockhash( instructions: &[Instruction], payer: Option<&Pubkey>, blockhash: &Hash, ) -> Self
Create a new message while setting the blockhash.
§Examples
This example uses the solana_sdk
, solana_rpc_client
and anyhow
crates.
use anyhow::Result;
use borsh::{BorshSerialize, BorshDeserialize};
use solana_rpc_client::rpc_client::RpcClient;
use solana_sdk::{
instruction::Instruction,
message::Message,
pubkey::Pubkey,
signature::{Keypair, Signer},
transaction::Transaction,
};
// A custom program instruction. This would typically be defined in
// another crate so it can be shared between the on-chain program and
// the client.
#[derive(BorshSerialize, BorshDeserialize)]
enum BankInstruction {
Initialize,
Deposit { lamports: u64 },
Withdraw { lamports: u64 },
}
fn send_initialize_tx(
client: &RpcClient,
program_id: Pubkey,
payer: &Keypair
) -> Result<()> {
let bank_instruction = BankInstruction::Initialize;
let instruction = Instruction::new_with_borsh(
program_id,
&bank_instruction,
vec![],
);
let blockhash = client.get_latest_blockhash()?;
let message = Message::new_with_blockhash(
&[instruction],
Some(&payer.pubkey()),
&blockhash,
);
let mut tx = Transaction::new_unsigned(message);
tx.sign(&[payer], tx.message.recent_blockhash);
client.send_and_confirm_transaction(&tx)?;
Ok(())
}
Sourcepub fn new_with_nonce(
instructions: Vec<Instruction>,
payer: Option<&Pubkey>,
nonce_account_pubkey: &Pubkey,
nonce_authority_pubkey: &Pubkey,
) -> Self
pub fn new_with_nonce( instructions: Vec<Instruction>, payer: Option<&Pubkey>, nonce_account_pubkey: &Pubkey, nonce_authority_pubkey: &Pubkey, ) -> Self
Create a new message for a nonced transaction.
In this type of transaction, the blockhash is replaced with a durable transaction nonce, allowing for extended time to pass between the transaction’s signing and submission to the blockchain.
§Examples
This example uses the solana_sdk
, solana_rpc_client
and anyhow
crates.
use anyhow::Result;
use borsh::{BorshSerialize, BorshDeserialize};
use solana_rpc_client::rpc_client::RpcClient;
use solana_sdk::{
hash::Hash,
instruction::Instruction,
message::Message,
nonce,
pubkey::Pubkey,
signature::{Keypair, Signer},
system_instruction,
transaction::Transaction,
};
// A custom program instruction. This would typically be defined in
// another crate so it can be shared between the on-chain program and
// the client.
#[derive(BorshSerialize, BorshDeserialize)]
enum BankInstruction {
Initialize,
Deposit { lamports: u64 },
Withdraw { lamports: u64 },
}
// Create a nonced transaction for later signing and submission,
// returning it and the nonce account's pubkey.
fn create_offline_initialize_tx(
client: &RpcClient,
program_id: Pubkey,
payer: &Keypair
) -> Result<(Transaction, Pubkey)> {
let bank_instruction = BankInstruction::Initialize;
let bank_instruction = Instruction::new_with_borsh(
program_id,
&bank_instruction,
vec![],
);
// This will create a nonce account and assign authority to the
// payer so they can sign to advance the nonce and withdraw its rent.
let nonce_account = make_nonce_account(client, payer)?;
let mut message = Message::new_with_nonce(
vec![bank_instruction],
Some(&payer.pubkey()),
&nonce_account,
&payer.pubkey()
);
// This transaction will need to be signed later, using the blockhash
// stored in the nonce account.
let tx = Transaction::new_unsigned(message);
Ok((tx, nonce_account))
}
fn make_nonce_account(client: &RpcClient, payer: &Keypair)
-> Result<Pubkey>
{
let nonce_account_address = Keypair::new();
let nonce_account_size = nonce::State::size();
let nonce_rent = client.get_minimum_balance_for_rent_exemption(nonce_account_size)?;
// Assigning the nonce authority to the payer so they can sign for the withdrawal,
// and we can throw away the nonce address secret key.
let create_nonce_instr = system_instruction::create_nonce_account(
&payer.pubkey(),
&nonce_account_address.pubkey(),
&payer.pubkey(),
nonce_rent,
);
let mut nonce_tx = Transaction::new_with_payer(&create_nonce_instr, Some(&payer.pubkey()));
let blockhash = client.get_latest_blockhash()?;
nonce_tx.sign(&[&payer, &nonce_account_address], blockhash);
client.send_and_confirm_transaction(&nonce_tx)?;
Ok(nonce_account_address.pubkey())
}
pub fn new_with_compiled_instructions( num_required_signatures: u8, num_readonly_signed_accounts: u8, num_readonly_unsigned_accounts: u8, account_keys: Vec<Pubkey>, recent_blockhash: Hash, instructions: Vec<CompiledInstruction>, ) -> Self
Sourcepub fn hash_raw_message(message_bytes: &[u8]) -> Hash
pub fn hash_raw_message(message_bytes: &[u8]) -> Hash
Compute the blake3 hash of a raw transaction message.
pub fn compile_instruction(&self, ix: &Instruction) -> CompiledInstruction
pub fn serialize(&self) -> Vec<u8> ⓘ
pub fn program_id(&self, instruction_index: usize) -> Option<&Pubkey>
pub fn program_index(&self, instruction_index: usize) -> Option<usize>
pub fn program_ids(&self) -> Vec<&Pubkey>
pub fn is_key_passed_to_program(&self, key_index: usize) -> bool
is_instruction_account
insteadSourcepub fn is_instruction_account(&self, key_index: usize) -> bool
pub fn is_instruction_account(&self, key_index: usize) -> bool
Returns true if the account at the specified index is an account input to some program instruction in this message.
pub fn is_key_called_as_program(&self, key_index: usize) -> bool
pub fn is_non_loader_key(&self, key_index: usize) -> bool
is_key_called_as_program
and is_instruction_account
directlypub fn program_position(&self, index: usize) -> Option<usize>
pub fn maybe_executable(&self, i: usize) -> bool
pub fn demote_program_id(&self, i: usize) -> bool
Sourcepub fn is_writable(&self, i: usize) -> bool
👎Deprecated since 2.0.0: Please use is_maybe_writable
instead
pub fn is_writable(&self, i: usize) -> bool
is_maybe_writable
insteadReturns true if the account at the specified index is writable by the instructions in this message. Since the dynamic set of reserved accounts isn’t used here to demote write locks, this shouldn’t be used in the runtime.
Sourcepub fn is_maybe_writable(
&self,
i: usize,
reserved_account_keys: Option<&HashSet<Pubkey>>,
) -> bool
pub fn is_maybe_writable( &self, i: usize, reserved_account_keys: Option<&HashSet<Pubkey>>, ) -> bool
Returns true if the account at the specified index is writable by the
instructions in this message. The reserved_account_keys
param has been
optional to allow clients to approximate writability without requiring
fetching the latest set of reserved account keys. If this method is
called by the runtime, the latest set of reserved account keys must be
passed.
pub fn is_signer(&self, i: usize) -> bool
pub fn signer_keys(&self) -> Vec<&Pubkey>
Sourcepub fn has_duplicates(&self) -> bool
pub fn has_duplicates(&self) -> bool
Returns true
if account_keys
has any duplicate keys.
Sourcepub fn is_upgradeable_loader_present(&self) -> bool
pub fn is_upgradeable_loader_present(&self) -> bool
Returns true
if any account is the BPF upgradeable loader.