Skip to content

Commit

Permalink
Add GlobalCfg, cli vm-backtrace option
Browse files Browse the repository at this point in the history
  • Loading branch information
rakita committed Dec 27, 2021
1 parent 07f1a3f commit 33a6129
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 14 deletions.
10 changes: 9 additions & 1 deletion fuel-core/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::service::{Config, DbType};
use crate::service::{Config, DbType, VMConfig};
use std::{env, io, net, path::PathBuf, string::ToString};
use structopt::StructOpt;
use tracing_subscriber::filter::EnvFilter;
Expand Down Expand Up @@ -29,6 +29,10 @@ pub struct Opt {
/// Specify either an alias to a built-in configuration or filepath to a JSON file.
#[structopt(name = "CHAIN_CONFIG", long = "chain", default_value = "local_testnet")]
pub chain_config: String,

/// Specify if backtraces are going to be traced in logs (Default false)
#[structopt(long = "vm-backtrace")]
pub vm_backtrace: bool,
}

impl Opt {
Expand All @@ -49,6 +53,7 @@ impl Opt {
database_path,
database_type,
chain_config,
vm_backtrace,
} = self;

let addr = net::SocketAddr::new(ip, port);
Expand All @@ -58,6 +63,9 @@ impl Opt {
database_path,
database_type,
chain_conf: chain_config.as_str().parse()?,
vm: VMConfig {
backtrace: vm_backtrace,
},
})
}
}
34 changes: 29 additions & 5 deletions fuel-core/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ use crate::{
use fuel_asm::Word;
use fuel_storage::Storage;
use fuel_tx::{Address, Bytes32, Color, Input, Output, Receipt, Transaction};
use fuel_vm::prelude::{Interpreter, InterpreterError};
use fuel_vm::{
consts::REG_SP,
prelude::{Backtrace as FuelBacktrace, Interpreter, InterpreterError},
};
use std::error::Error as StdError;
use std::ops::DerefMut;
use thiserror::Error;
use tracing::warn;

pub struct Executor {
pub database: Database,
}

impl Executor {
pub async fn execute(&self, block: &FuelBlock) -> Result<(), Error> {
pub async fn execute(&self, block: &FuelBlock, with_backtrace: bool) -> Result<(), Error> {
let mut block_tx = self.database.transaction();
let block_id = block.id();
Storage::<Bytes32, FuelBlock>::insert(block_tx.deref_mut(), &block_id, block)?;
Expand All @@ -41,9 +45,8 @@ impl Executor {

// execute vm
let mut vm = Interpreter::with_storage(tx_db.clone());
let execution_result = vm.transact(tx);

match execution_result {
let result = vm.transact(tx);
match result {
Ok(result) => {
// persist any outputs
self.persist_outputs(block.fuel_height, result.tx(), tx_db)?;
Expand All @@ -66,6 +69,19 @@ impl Executor {
}
// save error status on block_tx since the sub_tx changes are dropped
Err(e) => {
if with_backtrace {
if let Some(backtrace) = vm.backtrace() {
warn!(
target = "vm",
"Execution panic {:?} on contract: 0x{:x}\nregisters: {:?}\ncall_stack: {:?}\nstack\n: {}",
backtrace.error(),
backtrace.contract(),
backtrace.registers(),
backtrace.call_stack(),
hex::encode(&backtrace.memory()[..backtrace.registers()[REG_SP] as usize]), // print stack
);
}
}
block_tx.update_tx_status(
tx_id,
TransactionStatus::Failed {
Expand Down Expand Up @@ -264,6 +280,14 @@ pub enum Error {
},
#[error("VM execution error: {0:?}")]
VmExecution(fuel_vm::prelude::InterpreterError),
#[error("Execution error with backtrace")]
Backtrace(Box<FuelBacktrace>),
}

impl From<FuelBacktrace> for Error {
fn from(e: FuelBacktrace) -> Self {
Error::Backtrace(Box::new(e))
}
}

impl From<crate::database::KvStoreError> for Error {
Expand Down
7 changes: 5 additions & 2 deletions fuel-core/src/schema/tx.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::database::{transaction::OwnedTransactionIndexCursor, Database, KvStoreError};
use crate::model::fuel_block::{BlockHeight, FuelBlock};
use crate::schema::scalars::{HexString, HexString256, SortedTxCursor};
use crate::service::Config;
use crate::state::IterDirection;
use crate::tx_pool::TxPool;
use async_graphql::{
Expand Down Expand Up @@ -248,10 +249,11 @@ impl TxMutation {
tx: HexString,
) -> async_graphql::Result<Vec<receipt::Receipt>> {
let transaction = ctx.data_unchecked::<Database>().transaction();
let cfg = ctx.data_unchecked::<Config>();
let tx = FuelTx::from_bytes(&tx.0)?;
// make virtual txpool from transactional view
let tx_pool = TxPool::new(transaction.deref().clone());
let receipts = tx_pool.run_tx(tx).await?;
let receipts = tx_pool.run_tx(tx, cfg.vm.backtrace).await?;
Ok(receipts.into_iter().map(receipt::Receipt).collect())
}

Expand All @@ -262,8 +264,9 @@ impl TxMutation {
tx: HexString,
) -> async_graphql::Result<HexString256> {
let tx_pool = ctx.data::<Arc<TxPool>>().unwrap();
let cfg = ctx.data_unchecked::<Config>();
let tx = FuelTx::from_bytes(&tx.0)?;
let id = tx_pool.submit_tx(tx).await?;
let id = tx_pool.submit_tx(tx, cfg.vm.backtrace).await?;

Ok(id.into())
}
Expand Down
7 changes: 7 additions & 0 deletions fuel-core/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct Config {
pub database_path: PathBuf,
pub database_type: DbType,
pub chain_conf: ChainConfig,
pub vm: VMConfig,
}

impl Config {
Expand All @@ -35,10 +36,16 @@ impl Config {
database_path: Default::default(),
database_type: DbType::InMemory,
chain_conf: ChainConfig::local_testnet(),
vm: Default::default(),
}
}
}

#[derive(Clone, Debug, Default)]
pub struct VMConfig {
pub backtrace: bool,
}

#[derive(Clone, Debug, PartialEq, EnumString, Display)]
pub enum DbType {
InMemory,
Expand Down
5 changes: 3 additions & 2 deletions fuel-core/src/service/graph_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ pub async fn start_server(
db: Database,
tx_pool: Arc<TxPool>,
) -> Result<(SocketAddr, JoinHandle<Result<(), crate::service::Error>>), std::io::Error> {
let schema = build_schema().data(db).data(tx_pool);
let network_addr = config.addr;
let schema = build_schema().data(db).data(tx_pool).data(config);
let schema = dap::init(schema).finish();

let router = Router::new()
Expand All @@ -55,7 +56,7 @@ pub async fn start_server(
.boxed();

let (tx, rx) = tokio::sync::oneshot::channel();
let listener = TcpListener::bind(&config.addr)?;
let listener = TcpListener::bind(&network_addr)?;
let bound_addr = listener.local_addr().unwrap();

info!("Binding GraphQL provider to {}", bound_addr);
Expand Down
12 changes: 8 additions & 4 deletions fuel-core/src/tx_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl TxPool {
}
}

pub async fn submit_tx(&self, tx: Transaction) -> Result<Bytes32, Error> {
pub async fn submit_tx(&self, tx: Transaction, with_backtrace: bool) -> Result<Bytes32, Error> {
let tx_id = tx.id();
// persist transaction to database
let mut db = self.db.clone();
Expand All @@ -81,14 +81,18 @@ impl TxPool {
};
// immediately execute block
self.executor
.execute(&block)
.execute(&block, with_backtrace)
.await
.map_err(Error::Execution)?;
Ok(tx_id)
}

pub async fn run_tx(&self, tx: Transaction) -> Result<Vec<Receipt>, Error> {
let id = self.submit_tx(tx).await?;
pub async fn run_tx(
&self,
tx: Transaction,
with_backtraces: bool,
) -> Result<Vec<Receipt>, Error> {
let id = self.submit_tx(tx, with_backtraces).await?;
// note: we'll need to await tx completion once it's not instantaneous
let db = &self.db;
let receipts = Storage::<Bytes32, Vec<Receipt>>::get(db, &id)?.unwrap_or_default();
Expand Down

0 comments on commit 33a6129

Please sign in to comment.