Skip to content

Commit

Permalink
fix(executor): try add missing account during simulation stage
Browse files Browse the repository at this point in the history
  • Loading branch information
00nktk committed Nov 13, 2024
1 parent b0425d0 commit 2220376
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 33 deletions.
73 changes: 53 additions & 20 deletions executor/src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,33 +809,16 @@ impl TransactionBuilder {
alt: Option<AltInfo>,
) -> anyhow::Result<Option<OngoingTransaction>> {
let chain_id = get_chain_id(&tx_data.envelope.tx);
let tx_hash = tx_data.envelope.tx_hash();
let tx_hash = *tx_data.envelope.tx_hash();
let mut tx_data = tx_data;
let mut iter_info = match iter_info {
Some(iter_info) if iter_info.is_finished() => {
tracing::debug!(%tx_hash, "iterations finished");
return Ok(None);
}
Some(info) => info,
None => {
let build_tx = |iter_info: &mut IterInfo| {
let mut txs = Vec::new();
while !iter_info.is_finished() {
let ix = self.build_step(BuildStep::collect(
from_data,
iter_info,
&tx_data,
*holder.pubkey(),
))?;
txs.push(Transaction::new_with_payer(
&with_budget(ix, MAX_COMPUTE_UNITS),
Some(&self.pubkey()),
));
}
Ok(txs)
};

self.emulator
.calculate_iterations(tx_hash, &tx_data.emulate, build_tx)
self.prepare_iterations(&mut tx_data, *holder.pubkey(), from_data)
.await?
}
};
Expand All @@ -860,6 +843,56 @@ impl TransactionBuilder {
.map(Some)
}

async fn prepare_iterations(
&self,
tx_data: &mut TxData,
holder: Pubkey,
from_data: bool,
) -> anyhow::Result<IterInfo> {
// This is a huge number just to make sure we do not get stuck
// in an infinite missing accouunt error.
const SIMULATE_RETRIES: usize = 20;

let tx_hash = *tx_data.envelope.tx_hash();
for attempt in 0..SIMULATE_RETRIES {
let build_tx = |iter_info: &mut IterInfo| {
let mut txs = Vec::new();
while !iter_info.is_finished() {
let ix =
self.build_step(BuildStep::collect(from_data, iter_info, tx_data, holder))?;
txs.push(Transaction::new_with_payer(
&with_budget(ix, MAX_COMPUTE_UNITS),
Some(&self.pubkey()),
));
}
Ok(txs)
};

match self
.emulator
.calculate_iterations(&tx_hash, &tx_data.emulate, build_tx)
.await
{
Ok(info) => return Ok(info),
Err(emulator::Error::MissingAccount(pubkey)) => {
tracing::debug!(%tx_hash, ?pubkey, attempt, "adding missing account");
tx_data.emulate.solana_accounts.push(NeonSolanaAccount {
pubkey,
is_writable: true,
is_legacy: false,
})
}
Err(emulator::Error::Other(err)) => return Err(err),
}
}
let iter_info = self.emulator.default_iter_info(&tx_data.emulate);
tracing::warn!(
%tx_hash, ?iter_info,
"selected default iter info after {SIMULATE_RETRIES} unsuccessful attempts"
);
Ok(iter_info)
}

async fn recovered_step(
&self,
tx_hash: B256,
Expand Down
32 changes: 20 additions & 12 deletions executor/src/transactions/emulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,23 @@ use rust_decimal_macros::dec;
use solana_sdk::instruction::{Instruction, InstructionError};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::transaction::{Transaction, TransactionError};
use thiserror::Error;

use common::convert::ToNeon;
use neon_api::{NeonApi, SimulateConfig};

use crate::transactions::preflight_error::try_extract_missing_account;

use super::{MAX_COMPUTE_UNITS, MAX_HEAP_SIZE};

#[derive(Debug, Error)]
pub(super) enum Error {
#[error("missing account: {0}")]
MissingAccount(Pubkey),
#[error("{0}")]
Other(#[from] anyhow::Error),
}

#[derive(Clone, Debug)]
pub(super) struct IterInfo {
step_count: u32,
Expand Down Expand Up @@ -158,7 +169,7 @@ impl Emulator {
tx_hash: &B256,
emulate: &EmulateResponse,
f: impl FnMut(&mut IterInfo) -> anyhow::Result<Vec<Transaction>>,
) -> anyhow::Result<IterInfo> {
) -> Result<IterInfo, Error> {
const RETRIES: usize = 10;

let mut f = f;
Expand All @@ -177,8 +188,6 @@ impl Emulator {
break;
}

// let exec_iter =
// (total_steps / iter_steps) + if total_steps % iter_steps > 1 { 1 } else { 0 };
let iterations = exec_iter + wrap_iter;
tracing::debug!(%tx_hash, iter_steps, total_steps, iterations, "testing iter_info");

Expand All @@ -194,6 +203,14 @@ impl Emulator {
tracing::debug!(%tx_hash, try_idx = retry, "simulation errored");
for (tx_idx, res) in res.iter().enumerate() {
tracing::debug!(%tx_hash, tx_idx, try_idx = retry, ?res, "simulation report");
if let Some(key) = res
.logs
.iter()
.rev()
.find_map(|log| try_extract_missing_account(log))
{
return Err(Error::MissingAccount(key));
}
}
}

Expand All @@ -213,15 +230,6 @@ impl Emulator {
return Ok(iter_info);
}

// let ratio = dec!(0.9).min(
// Decimal::from(max_cu_limit)
// .checked_div(used_cu_limit.into())
// .unwrap_or(Decimal::MAX),
// );
// iter_steps = self
// .evm_steps_min
// .load(Relaxed)
// .max(ratio.saturating_mul(iter_steps.into()).try_into()?);
exec_iter += 1;
iter_steps =
(total_steps / exec_iter) + if total_steps % exec_iter > 0 { 1 } else { 0 };
Expand Down
2 changes: 1 addition & 1 deletion executor/src/transactions/preflight_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fn extract_transaction_err(err: &ClientErrorKind) -> Option<&TransactionError> {
}
}

fn try_extract_missing_account(log: &str) -> Option<Pubkey> {
pub fn try_extract_missing_account(log: &str) -> Option<Pubkey> {
let log = log.strip_prefix("Program log: panicked at 'address ")?;
let end = log.find(" must be present in the transaction'")?;
log[0..end].parse().ok()
Expand Down

0 comments on commit 2220376

Please sign in to comment.