diff --git a/client/src/client.rs b/client/src/client.rs index b123e020b..652d1098a 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -18,7 +18,7 @@ use solana_sdk::{ signature::{Keypair, Signature, Signer}, signers::Signers, system_instruction, - transaction::Transaction, + transaction::{Transaction, VersionedTransaction}, message::{VersionedMessage, v0}, address_lookup_table_account::AddressLookupTableAccount, }; use std::{ fmt::Debug, @@ -111,6 +111,19 @@ impl Client { tx.sign(signers, self.latest_blockhash()?); Ok(self.send_transaction(&tx)?) } + + pub fn send_versioned_tx(&self, ixs: &[Instruction], signers: &T, address_lookup_tables: &[AddressLookupTableAccount]) -> ClientResult { + let tx = VersionedTransaction::try_new( + VersionedMessage::V0(v0::Message::try_compile( + &self.payer_pubkey(), + &ixs, + &address_lookup_tables, + self.latest_blockhash()?, + ).expect("error compiling to v0 message")), + signers, + ).expect("error creating new versioned transaction"); + Ok(self.send_transaction(&tx)?) + } pub fn send_with_config( &self, @@ -121,6 +134,25 @@ impl Client { let tx = self.transaction(ixs, signers)?; Ok(self.client.send_transaction_with_config(&tx, config)?) } + + pub fn send_versioned_tx_with_config( + &self, + ixs: &[Instruction], + signers: &T, + address_lookup_tables: &[AddressLookupTableAccount], + config: RpcSendTransactionConfig, + ) -> ClientResult { + let tx = VersionedTransaction::try_new( + VersionedMessage::V0(v0::Message::try_compile( + &self.payer_pubkey(), + &ixs, + &address_lookup_tables, + self.latest_blockhash()?, + ).expect("error compiling to v0 message")), + signers, + ).expect("error creating new versioned transaction"); + Ok(self.client.send_transaction_with_config(&tx, config)?) + } pub fn send_and_confirm( &self, @@ -131,6 +163,24 @@ impl Client { Ok(self.send_and_confirm_transaction(&tx)?) } + pub fn send_and_confirm_versioned_tx( + &self, + ixs: &[Instruction], + signers: &T, + address_lookup_tables: &[AddressLookupTableAccount] + ) -> ClientResult { + let tx = VersionedTransaction::try_new( + VersionedMessage::V0(v0::Message::try_compile( + &self.payer_pubkey(), + &ixs, + &address_lookup_tables, + self.latest_blockhash()?, + ).expect("error compiling to v0 message")), + signers, + ).expect("error creating new versioned transaction"); + Ok(self.send_and_confirm_transaction(&tx)?) + } + pub fn simulate_transaction( &self, ixs: &[Instruction], @@ -144,6 +194,21 @@ impl Client { Ok(result.value) } } + + pub fn simulate_versioned_transaction( + &self, + ixs: &[Instruction], + signers: &T, + address_lookup_tables: &[AddressLookupTableAccount] + ) -> ClientResult { + let tx = self.versioned_transaction(ixs, signers, address_lookup_tables)?; + let result = self.client.simulate_transaction(&tx)?; + if result.value.err.is_some() { + Err(ClientError::DeserializationError) + } else { + Ok(result.value) + } + } fn transaction( &self, @@ -154,6 +219,26 @@ impl Client { tx.sign(signers, self.latest_blockhash()?); Ok(tx) } + + fn versioned_transaction( + &self, + ixs: &[Instruction], + signers: &T, + address_lookup_tables: &[AddressLookupTableAccount] + ) -> ClientResult { + // let mut tx = Transaction::new_with_payer(ixs, Some(&self.payer_pubkey())); + // tx.sign(signers, self.latest_blockhash()?); + let tx = VersionedTransaction::try_new( + VersionedMessage::V0(v0::Message::try_compile( + &self.payer_pubkey(), + &ixs, + &address_lookup_tables, + self.latest_blockhash()?, + ).expect("error compiling to v0 message")), + signers, + ).expect("error creating new versioned transaction"); + Ok(tx) + } } impl Debug for Client { diff --git a/plugin/src/builders/pool_rotation.rs b/plugin/src/builders/pool_rotation.rs index 712eb9499..dd5ba8356 100644 --- a/plugin/src/builders/pool_rotation.rs +++ b/plugin/src/builders/pool_rotation.rs @@ -3,7 +3,8 @@ use std::sync::Arc; use clockwork_client::network::state::{Pool, Registry, Snapshot, SnapshotFrame, Worker}; use log::info; use solana_client::nonblocking::rpc_client::RpcClient; -use solana_sdk::{signature::Keypair, signer::Signer, transaction::Transaction}; +use solana_program::message::{VersionedMessage, v0}; +use solana_sdk::{signature::Keypair, signer::Signer, transaction::{VersionedTransaction}}; use crate::pool_position::PoolPosition; @@ -15,7 +16,7 @@ pub async fn build_pool_rotation_tx<'a>( snapshot: Snapshot, snapshot_frame: SnapshotFrame, worker_id: u64, -) -> Option { +) -> Option { info!("nonce: {:?} total_stake: {:?} current_position: {:?} stake_offset: {:?} stake_amount: {:?}", registry.nonce.checked_rem(snapshot.total_stake), snapshot.total_stake, @@ -70,8 +71,89 @@ pub async fn build_pool_rotation_tx<'a>( Worker::pubkey(worker_id), ); + // let mut tx = Transaction::new_with_payer(&[ix.clone()], Some(&keypair.pubkey())); + // tx.sign(&[keypair], client.get_latest_blockhash().await.unwrap()); + // Build and sign tx. - let mut tx = Transaction::new_with_payer(&[ix.clone()], Some(&keypair.pubkey())); - tx.sign(&[keypair], client.get_latest_blockhash().await.unwrap()); + let blockhash = client.get_latest_blockhash().await.unwrap(); + + let tx = VersionedTransaction::try_new( + VersionedMessage::V0(v0::Message::try_compile( + &keypair.pubkey(), + &[ix.clone()], + &[], + blockhash, + ).expect("error compiling to v0 message")), + &[keypair], + ).expect("error creating new versioned transaction"); return Some(tx); } + +// pub async fn build_pool_rotation_tx<'a>( +// client: Arc, +// keypair: &Keypair, +// pool_position: PoolPosition, +// registry: Registry, +// snapshot: Snapshot, +// snapshot_frame: SnapshotFrame, +// worker_id: u64, +// ) -> Option { +// info!("nonce: {:?} total_stake: {:?} current_position: {:?} stake_offset: {:?} stake_amount: {:?}", +// registry.nonce.checked_rem(snapshot.total_stake), +// snapshot.total_stake, +// pool_position.current_position, +// snapshot_frame.stake_offset, +// snapshot_frame.stake_amount, +// ); + +// // Exit early if the rotator is not intialized +// if registry.nonce == 0 { +// return None; +// } + +// // Exit early the snapshot has no stake +// if snapshot.total_stake == 0 { +// return None; +// } + +// // Exit early if the worker is already in the pool. +// if pool_position.current_position.is_some() { +// return None; +// } + +// // Exit early if the snapshot frame is none or the worker has no delegated stake. +// if snapshot_frame.stake_amount.eq(&0) { +// return None; +// } + +// // Check if the rotation window is open for this worker. +// let is_rotation_window_open = match registry.nonce.checked_rem(snapshot.total_stake) { +// None => false, +// Some(sample) => { +// sample >= snapshot_frame.stake_offset +// && sample +// < snapshot_frame +// .stake_offset +// .checked_add(snapshot_frame.stake_amount) +// .unwrap() +// } +// }; +// if !is_rotation_window_open { +// return None; +// } + +// // Build rotation instruction to rotate the worker into pool 0. +// let snapshot_pubkey = Snapshot::pubkey(snapshot.id); +// let ix = clockwork_client::network::instruction::pool_rotate( +// Pool::pubkey(0), +// keypair.pubkey(), +// snapshot_pubkey, +// SnapshotFrame::pubkey(snapshot_pubkey, worker_id), +// Worker::pubkey(worker_id), +// ); + +// // Build and sign tx. +// let mut tx = Transaction::new_with_payer(&[ix.clone()], Some(&keypair.pubkey())); +// tx.sign(&[keypair], client.get_latest_blockhash().await.unwrap()); +// return Some(tx); +// } diff --git a/plugin/src/executors/tx.rs b/plugin/src/executors/tx.rs index 0e340c6d2..16d3d0bde 100644 --- a/plugin/src/executors/tx.rs +++ b/plugin/src/executors/tx.rs @@ -25,7 +25,7 @@ use solana_program::pubkey::Pubkey; use solana_sdk::{ commitment_config::CommitmentConfig, signature::{Keypair, Signature}, - transaction::Transaction, + transaction::{VersionedTransaction}, }; use tokio::{runtime::Runtime, sync::RwLock}; @@ -378,7 +378,7 @@ impl TxExecutor { observed_slot: u64, due_slot: u64, thread_pubkey: Pubkey, - ) -> Option<(Pubkey, Transaction)> { + ) -> Option<(Pubkey, VersionedTransaction)> { let thread = match client.clone().get::(&thread_pubkey).await { Err(_err) => { self.increment_simulation_failure(thread_pubkey).await; @@ -388,8 +388,9 @@ impl TxExecutor { }; let lookup_tables_key = LookupTables::pubkey(thread.authority(), thread.pubkey()); - - let address_lookup_tables = match client.clone().get_lookup_tables(&lookup_tables_key).await { + + let address_lookup_tables = match client.clone().get_lookup_tables(&lookup_tables_key).await + { Err(_err) => { return None; } @@ -403,7 +404,7 @@ impl TxExecutor { thread, thread_pubkey, self.config.worker_id, - address_lookup_tables + address_lookup_tables, ) .await { @@ -439,7 +440,7 @@ impl TxExecutor { self: Arc, slot: u64, thread_pubkey: Pubkey, - tx: &Transaction, + tx: &VersionedTransaction, ) -> PluginResult<()> { let r_transaction_history = self.transaction_history.read().await; if let Some(metadata) = r_transaction_history.get(&thread_pubkey) { @@ -451,7 +452,10 @@ impl TxExecutor { Ok(()) } - async fn simulate_tx(self: Arc, tx: &Transaction) -> PluginResult { + async fn simulate_tx( + self: Arc, + tx: &VersionedTransaction, + ) -> PluginResult { TPU_CLIENT .get() .await @@ -480,14 +484,27 @@ impl TxExecutor { })? } - async fn submit_tx(self: Arc, tx: &Transaction) -> PluginResult { - if !TPU_CLIENT.get().await.send_transaction(tx).await { + async fn submit_tx( + self: Arc, + tx: &VersionedTransaction, + ) -> PluginResult { + let serialized_tx = serialize(&tx).unwrap(); + + if !TPU_CLIENT.get().await.send_wire_transaction(serialized_tx).await { return Err(GeyserPluginError::Custom( "Failed to send transaction".into(), )); } Ok(tx.clone()) } + // async fn submit_tx(self: Arc, tx: &Transaction) -> PluginResult { + // if !TPU_CLIENT.get().await.send_transaction(tx).await { + // return Err(GeyserPluginError::Custom( + // "Failed to send transaction".into(), + // )); + // } + // Ok(tx.clone()) + // } } impl Debug for TxExecutor { diff --git a/programs/thread/src/instructions/thread_lookup_tables_create.rs b/programs/thread/src/instructions/thread_lookup_tables_create.rs index 0731239fb..1a6565347 100644 --- a/programs/thread/src/instructions/thread_lookup_tables_create.rs +++ b/programs/thread/src/instructions/thread_lookup_tables_create.rs @@ -8,7 +8,7 @@ use anchor_lang::{ use crate::state::*; -/// Accounts required by the `thread_create` instruction. +/// Accounts required by the `thread_lookup_tables_create` instruction. #[derive(Accounts)] #[instruction(address_lookup_tables: Vec)] pub struct LookupTablesCreate<'info> { @@ -36,7 +36,7 @@ pub struct LookupTablesCreate<'info> { )] pub thread: Account<'info, Thread>, - /// The thread to be created. + /// The lookup_tables account to be created. #[account( init, seeds = [