Skip to content

Commit

Permalink
[client-rs] tx builder with option to not check signers (#8)
Browse files Browse the repository at this point in the history
* [client-rs] tx builder with option to not check signers

* [review] fix for wrong sig_verify
  • Loading branch information
ochaloup authored Oct 11, 2024
1 parent b616a67 commit 3f12093
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 27 deletions.
2 changes: 1 addition & 1 deletion libs/dynsigner/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Keypair;
use solana_sdk::signer::Signer;
use std::sync::Arc;
use solana_sdk::signature::Keypair;

/// Auxiliary data structure to align the types of the solana-clap-utils with anchor-client.
pub struct DynSigner(pub Arc<dyn Signer>);
Expand Down
2 changes: 1 addition & 1 deletion libs/marinade-client-rs/src/marinade/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ use dynsigner::PubkeyOrKeypair;
use marinade_finance::instructions::{ChangeAuthorityData, ConfigMarinadeParams};
use marinade_finance::state::Fee;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Keypair;
use solana_sdk::signer::Signer;
use std::ops::Deref;
use std::sync::Arc;
use solana_sdk::signature::Keypair;

pub trait MarinadeRequestBuilder<'a, C> {
fn add_validator(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::transactions::signature_builder::SignatureBuilder;
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signer::keypair::Keypair;
use solana_sdk::signer::SignerError;
use solana_sdk::transaction::Transaction;
use std::sync::Arc;
use solana_sdk::signer::keypair::Keypair;

pub struct PreparedTransaction {
pub transaction: Transaction,
Expand All @@ -23,6 +23,13 @@ impl PreparedTransaction {
})
}

pub fn new_no_signers(transaction: Transaction) -> Self {
Self {
transaction,
signers: vec![],
}
}

pub fn sign(&mut self, recent_blockhash: Hash) -> Result<&Transaction, SignerError> {
self.transaction.try_sign(
&self
Expand Down
32 changes: 27 additions & 5 deletions libs/marinade-client-rs/src/transactions/signature_builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use log::error;
use log::{debug, error};
use solana_sdk::{
pubkey::Pubkey,
signature::{Keypair, Signature, Signer, SignerError},
Expand All @@ -7,12 +7,27 @@ use solana_sdk::{
};
use std::{collections::HashMap, sync::Arc};

#[derive(Debug, Default)]
#[derive(Debug)]
pub struct SignatureBuilder {
pub signers: HashMap<Pubkey, Arc<Keypair>>,
pub is_check_signers: bool,
}

impl SignatureBuilder {
pub fn new() -> Self {
Self {
is_check_signers: true,
signers: HashMap::new(),
}
}

pub fn new_without_check() -> Self {
Self {
is_check_signers: false,
..SignatureBuilder::new()
}
}

pub fn add_signer(&mut self, signer: Arc<Keypair>) -> Pubkey {
let pubkey = signer.pubkey();
self.signers.insert(pubkey, signer);
Expand Down Expand Up @@ -47,9 +62,16 @@ impl SignatureBuilder {
if let Some(keypair) = self.signers.get(&key) {
transaction.signatures[pos] = keypair.try_sign_message(&message)?;
} else {
error!("sign_transaction: not enough signers, expected key: {}, available keys in builder: {:?}",
key, self.signers.keys().collect::<Vec<&Pubkey>>());
return Err(SignerError::NotEnoughSigners);
let error_msg = format!(
"sign_transaction: not enough signers, expected key: {}, available keys in builder: {:?}",
key, self.signers.keys().collect::<Vec<&Pubkey>>()
);
if self.is_check_signers {
error!("{}", error_msg);
return Err(SignerError::NotEnoughSigners);
} else {
debug!("{}", error_msg);
}
}
}
Ok(())
Expand Down
50 changes: 39 additions & 11 deletions libs/marinade-client-rs/src/transactions/transaction_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use anyhow::anyhow;
use log::error;
use once_cell::sync::OnceCell;
use solana_sdk::{
instruction::Instruction, packet::PACKET_DATA_SIZE, pubkey::Pubkey, signature::{Signer, Keypair},
instruction::Instruction,
packet::PACKET_DATA_SIZE,
pubkey::Pubkey,
signature::{Keypair, Signer},
transaction::Transaction,
};
use std::ops::Deref;
Expand All @@ -27,22 +30,31 @@ pub struct TransactionBuilder {
instruction_packs: Vec<Vec<Instruction>>,
current_instruction_pack: OnceCell<Vec<Instruction>>,
max_transaction_size: usize,
is_check_signers: bool,
}

impl TransactionBuilder {
pub fn new(fee_payer: Arc<Keypair>, max_transaction_size: usize) -> Self {
let mut signature_builder = SignatureBuilder::default();
let mut signature_builder = SignatureBuilder::new();
let fee_payer = signature_builder.add_signer(fee_payer);
let builder = Self {
fee_payer: signature_builder.add_signer(fee_payer),
fee_payer,
signature_builder,
instruction_packs: Vec::new(),
current_instruction_pack: OnceCell::new(),
max_transaction_size,
is_check_signers: true,
};
builder.current_instruction_pack.set(Vec::new()).unwrap();
builder
}

pub fn with_no_signers_check(mut self) -> Self {
self.is_check_signers = false;
self.signature_builder = SignatureBuilder::new_without_check();
self
}

pub fn fee_payer(&self) -> Pubkey {
self.fee_payer
}
Expand Down Expand Up @@ -80,6 +92,10 @@ impl TransactionBuilder {
}

fn check_signers(&self, instruction: &Instruction) -> Result<(), TransactionBuildError> {
if !self.is_check_signers {
return Ok(());
}

for account in &instruction.accounts {
if account.is_signer && !self.signature_builder.contains_key(&account.pubkey) {
error!(
Expand All @@ -97,6 +113,10 @@ impl TransactionBuilder {
Ok(())
}

pub fn is_check_signers(&self) -> bool {
self.is_check_signers
}

#[inline]
pub fn finish_instruction_pack(&mut self) {
self.instruction_packs.push(
Expand Down Expand Up @@ -187,10 +207,14 @@ impl TransactionBuilder {
let instructions: Vec<Instruction> =
self.instruction_packs.remove(0).into_iter().collect();
let transaction = Transaction::new_with_payer(&instructions, Some(&self.fee_payer));
Some(
PreparedTransaction::new(transaction, &self.signature_builder)
.expect("Signature keys must be checked when instruction added"),
)
if self.is_check_signers() {
Some(
PreparedTransaction::new(transaction, &self.signature_builder)
.expect("Signature keys must be checked when instruction added"),
)
} else {
Some(PreparedTransaction::new_no_signers(transaction))
}
} else {
None
}
Expand Down Expand Up @@ -244,10 +268,14 @@ impl TransactionBuilder {
}
transaction
};
Some(
PreparedTransaction::new(transaction, &self.signature_builder)
.expect("Signature keys must be checked when instruction added"),
)
if self.is_check_signers() {
Some(
PreparedTransaction::new(transaction, &self.signature_builder)
.expect("Signature keys must be checked when instruction added"),
)
} else {
Some(PreparedTransaction::new_no_signers(transaction))
}
}

pub fn build_single_combined(&mut self) -> Option<PreparedTransaction> {
Expand Down
26 changes: 19 additions & 7 deletions libs/marinade-client-rs/src/transactions/transaction_executors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,33 @@ pub fn log_execution(
}

pub trait TransactionSimulator {
fn simulate(&self, rpc_client: &RpcClient, sig_verify: bool) -> RpcResult<RpcSimulateTransactionResult>;
fn simulate(
&self,
rpc_client: &RpcClient,
sig_verify: bool,
) -> RpcResult<RpcSimulateTransactionResult>;
}

impl<'a, C: Deref<Target = impl Signer> + Clone> TransactionSimulator for RequestBuilder<'a, C> {
fn simulate(&self, rpc_client: &RpcClient, sig_verify: bool) -> RpcResult<RpcSimulateTransactionResult> {
fn simulate(
&self,
rpc_client: &RpcClient,
sig_verify: bool,
) -> RpcResult<RpcSimulateTransactionResult> {
let tx = self.signed_transaction().map_err(|err| {
error!(
"RequestBuilder#simulate: cannot build transactions from builder: {:?}",
err
);
ForUser(format!("Building transaction error: {}", err))
})?;
rpc_client.simulate_transaction_with_config(&tx, RpcSimulateTransactionConfig {
sig_verify,
..RpcSimulateTransactionConfig::default()
})
rpc_client.simulate_transaction_with_config(
&tx,
RpcSimulateTransactionConfig {
sig_verify,
..RpcSimulateTransactionConfig::default()
},
)
}
}

Expand Down Expand Up @@ -220,6 +231,7 @@ pub fn execute_transaction_builder(
// expecting the instructions are dependent one to each other
// the result of the first can be used in the next one, for that simulation is run only for the fist bunch
let mut number_of_transactions = 0_u32;
let is_checked_signers = transaction_builder.is_check_signers();
for mut prepared_transaction in transaction_builder.sequence_combined() {
number_of_transactions += 1;
if number_of_transactions > 1 {
Expand All @@ -239,7 +251,7 @@ pub fn execute_transaction_builder(
&mut prepared_transaction,
rpc_client,
RpcSimulateTransactionConfig {
sig_verify: !print,
sig_verify: !print && is_checked_signers,
commitment: simulation_commitment,
encoding: preflight_config.encoding,
min_context_slot: preflight_config.min_context_slot,
Expand Down
2 changes: 1 addition & 1 deletion libs/marinade-common-cli/src/matchers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use solana_clap_utils::input_parsers::pubkey_of_signer;
use solana_clap_utils::keypair::{keypair_from_path, signer_from_path};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Keypair;
use solana_sdk::signer::Signer;
use std::{str::FromStr, sync::Arc};
use solana_sdk::signature::Keypair;

// Getting keypair from the matched name as the keypair path argument, or returns the default signer
pub fn keypair_from_path_or_default(
Expand Down

0 comments on commit 3f12093

Please sign in to comment.