1- use std:: sync:: Arc ;
1+ use std:: collections:: HashSet ;
2+ use std:: sync:: { Arc , Mutex , RwLock } ;
23
34use anchor_lang:: { InstructionData , ToAccountMetas } ;
45use log:: info;
@@ -33,14 +34,17 @@ static TRANSACTION_COMPUTE_UNIT_LIMIT: u32 = 1_400_000;
3334/// The buffer amount to add to transactions' compute units in case on-chain PDA derivations take more CUs than used in simulation.
3435static TRANSACTION_COMPUTE_UNIT_BUFFER : u32 = 1000 ;
3536
37+ pub const INSTRUCTION_ERROR_REENTRANCY_NOT_ALLOWED : i64 = 4615034 ;
38+ pub const INSTRUCTION_ERROR_ANCHOR_ACCOUNT_OWNED_BY_WRONG_PROGRAM : i64 = 3007 ;
39+
3640pub async fn build_thread_exec_tx (
3741 client : Arc < RpcClient > ,
3842 payer : & Keypair ,
3943 slot : u64 ,
4044 thread : VersionedThread ,
4145 thread_pubkey : Pubkey ,
4246 worker_id : u64 ,
43- ) -> Result < Option < Transaction > , PluginError > {
47+ ) -> Result < ( Option < Transaction > , /* Blacklisted */ Option < Pubkey > ) , PluginError > {
4448 // Grab the thread and relevant data.
4549 let now = std:: time:: Instant :: now ( ) ;
4650 let blockhash = client. get_latest_blockhash ( ) . await ?;
@@ -102,10 +106,25 @@ pub async fn build_thread_exec_tx(
102106 {
103107 // If there was a simulation error, stop packing and exit now.
104108 Err ( err) => {
109+ // Check for specific error and blacklist the thread
105110 if let solana_client:: client_error:: ClientErrorKind :: RpcError (
106111 solana_client:: rpc_request:: RpcError :: RpcResponseError { code, .. } ,
107112 ) = err. kind
108113 {
114+ if code == INSTRUCTION_ERROR_REENTRANCY_NOT_ALLOWED {
115+ info ! (
116+ "INSTRUCTION_ERROR_REENTRANCY_NOT_ALLOWED, blacklisting thread: {}" ,
117+ thread_pubkey
118+ ) ;
119+ return Ok ( ( None , Some ( thread_pubkey) ) ) ;
120+ }
121+ if code == INSTRUCTION_ERROR_ANCHOR_ACCOUNT_OWNED_BY_WRONG_PROGRAM {
122+ info ! (
123+ "INSTRUCTION_ERROR_ANCHOR_ACCOUNT_OWNED_BY_WRONG_PROGRAM, blacklisting thread: {}" ,
124+ thread_pubkey
125+ ) ;
126+ return Ok ( ( None , Some ( thread_pubkey) ) ) ;
127+ }
109128 if code == JSON_RPC_SERVER_ERROR_MIN_CONTEXT_SLOT_NOT_REACHED {
110129 return Err ( PluginError :: MinContextSlotNotReached ) ;
111130 }
@@ -172,7 +191,7 @@ pub async fn build_thread_exec_tx(
172191 // If there were no successful instructions, then exit early. There is nothing to do.
173192 // Alternatively, exit early if only the kickoff instruction (and no execs) succeeded.
174193 if successful_ixs. is_empty ( ) {
175- return Ok ( None ) ;
194+ return Ok ( ( None , None ) ) ;
176195 }
177196
178197 // Set the transaction's compute unit limit to be exactly the amount that was used in simulation.
@@ -199,7 +218,7 @@ pub async fn build_thread_exec_tx(
199218 units_consumed,
200219 tx. signatures[ 0 ]
201220 ) ;
202- Ok ( Some ( tx) )
221+ Ok ( ( Some ( tx) , None ) )
203222}
204223
205224fn build_kickoff_ix (
0 commit comments