2021-09-30 14:26:17 -07:00
|
|
|
use {
|
|
|
|
crate::{
|
|
|
|
accounts_update_notifier::AccountsUpdateNotifierImpl,
|
2021-12-29 15:12:01 -08:00
|
|
|
block_metadata_notifier::BlockMetadataNotifierImpl,
|
|
|
|
block_metadata_notifier_interface::BlockMetadataNotifierLock,
|
2022-03-14 18:18:46 -07:00
|
|
|
geyser_plugin_manager::GeyserPluginManager, slot_status_notifier::SlotStatusNotifierImpl,
|
|
|
|
slot_status_observer::SlotStatusObserver, transaction_notifier::TransactionNotifierImpl,
|
2021-09-30 14:26:17 -07:00
|
|
|
},
|
|
|
|
crossbeam_channel::Receiver,
|
|
|
|
log::*,
|
2021-11-23 09:55:53 -08:00
|
|
|
solana_rpc::{
|
|
|
|
optimistically_confirmed_bank_tracker::BankNotification,
|
|
|
|
transaction_notifier_interface::TransactionNotifierLock,
|
|
|
|
},
|
2021-09-30 14:26:17 -07:00
|
|
|
solana_runtime::accounts_update_notifier_interface::AccountsUpdateNotifier,
|
|
|
|
std::{
|
|
|
|
fs::File,
|
|
|
|
io::Read,
|
2021-10-08 20:06:58 -07:00
|
|
|
path::{Path, PathBuf},
|
2021-09-30 14:26:17 -07:00
|
|
|
sync::{Arc, RwLock},
|
|
|
|
thread,
|
|
|
|
},
|
|
|
|
thiserror::Error,
|
|
|
|
};
|
|
|
|
|
|
|
|
#[derive(Error, Debug)]
|
2022-03-14 18:18:46 -07:00
|
|
|
pub enum GeyserPluginServiceError {
|
2021-09-30 14:26:17 -07:00
|
|
|
#[error("Cannot open the the plugin config file")]
|
|
|
|
CannotOpenConfigFile(String),
|
|
|
|
|
|
|
|
#[error("Cannot read the the plugin config file")]
|
|
|
|
CannotReadConfigFile(String),
|
|
|
|
|
|
|
|
#[error("The config file is not in a valid Json format")]
|
|
|
|
InvalidConfigFileFormat(String),
|
|
|
|
|
|
|
|
#[error("Plugin library path is not specified in the config file")]
|
|
|
|
LibPathNotSet,
|
|
|
|
|
|
|
|
#[error("Invalid plugin path")]
|
|
|
|
InvalidPluginPath,
|
|
|
|
|
|
|
|
#[error("Cannot load plugin shared library")]
|
|
|
|
PluginLoadError(String),
|
|
|
|
}
|
|
|
|
|
2022-03-14 18:18:46 -07:00
|
|
|
/// The service managing the Geyser plugin workflow.
|
|
|
|
pub struct GeyserPluginService {
|
2021-11-17 17:11:38 -08:00
|
|
|
slot_status_observer: Option<SlotStatusObserver>,
|
2022-03-14 18:18:46 -07:00
|
|
|
plugin_manager: Arc<RwLock<GeyserPluginManager>>,
|
2021-11-17 17:11:38 -08:00
|
|
|
accounts_update_notifier: Option<AccountsUpdateNotifier>,
|
2021-11-23 09:55:53 -08:00
|
|
|
transaction_notifier: Option<TransactionNotifierLock>,
|
2021-12-29 15:12:01 -08:00
|
|
|
block_metadata_notifier: Option<BlockMetadataNotifierLock>,
|
2021-09-30 14:26:17 -07:00
|
|
|
}
|
|
|
|
|
2022-03-14 18:18:46 -07:00
|
|
|
impl GeyserPluginService {
|
|
|
|
/// Creates and returns the GeyserPluginService.
|
2021-09-30 14:26:17 -07:00
|
|
|
/// # Arguments
|
|
|
|
/// * `confirmed_bank_receiver` - The receiver for confirmed bank notification
|
2022-03-14 18:18:46 -07:00
|
|
|
/// * `geyser_plugin_config_file` - The config file path for the plugin. The
|
2021-09-30 14:26:17 -07:00
|
|
|
/// config file controls the plugin responsible
|
|
|
|
/// for transporting the data to external data stores. It is defined in JSON format.
|
|
|
|
/// The `libpath` field should be pointed to the full path of the dynamic shared library
|
2022-03-14 18:18:46 -07:00
|
|
|
/// (.so file) to be loaded. The shared library must implement the `GeyserPlugin`
|
2021-09-30 14:26:17 -07:00
|
|
|
/// trait. And the shared library shall export a `C` function `_create_plugin` which
|
2022-03-14 18:18:46 -07:00
|
|
|
/// shall create the implementation of `GeyserPlugin` and returns to the caller.
|
2021-09-30 14:26:17 -07:00
|
|
|
/// The rest of the JSON fields' definition is up to to the concrete plugin implementation
|
|
|
|
/// It is usually used to configure the connection information for the external data store.
|
|
|
|
|
|
|
|
pub fn new(
|
|
|
|
confirmed_bank_receiver: Receiver<BankNotification>,
|
2022-03-14 18:18:46 -07:00
|
|
|
geyser_plugin_config_files: &[PathBuf],
|
|
|
|
) -> Result<Self, GeyserPluginServiceError> {
|
2021-09-30 14:26:17 -07:00
|
|
|
info!(
|
2022-03-14 18:18:46 -07:00
|
|
|
"Starting GeyserPluginService from config files: {:?}",
|
|
|
|
geyser_plugin_config_files
|
2021-09-30 14:26:17 -07:00
|
|
|
);
|
2022-03-14 18:18:46 -07:00
|
|
|
let mut plugin_manager = GeyserPluginManager::new();
|
2021-10-08 20:06:58 -07:00
|
|
|
|
2022-03-14 18:18:46 -07:00
|
|
|
for geyser_plugin_config_file in geyser_plugin_config_files {
|
|
|
|
Self::load_plugin(&mut plugin_manager, geyser_plugin_config_file)?;
|
2021-10-08 20:06:58 -07:00
|
|
|
}
|
2021-11-23 09:55:53 -08:00
|
|
|
let account_data_notifications_enabled =
|
|
|
|
plugin_manager.account_data_notifications_enabled();
|
|
|
|
let transaction_notifications_enabled = plugin_manager.transaction_notifications_enabled();
|
2021-10-08 20:06:58 -07:00
|
|
|
|
2021-09-30 14:26:17 -07:00
|
|
|
let plugin_manager = Arc::new(RwLock::new(plugin_manager));
|
2021-11-17 17:11:38 -08:00
|
|
|
|
2021-11-23 09:55:53 -08:00
|
|
|
let accounts_update_notifier: Option<AccountsUpdateNotifier> =
|
|
|
|
if account_data_notifications_enabled {
|
|
|
|
let accounts_update_notifier =
|
|
|
|
AccountsUpdateNotifierImpl::new(plugin_manager.clone());
|
|
|
|
Some(Arc::new(RwLock::new(accounts_update_notifier)))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
let transaction_notifier: Option<TransactionNotifierLock> =
|
|
|
|
if transaction_notifications_enabled {
|
|
|
|
let transaction_notifier = TransactionNotifierImpl::new(plugin_manager.clone());
|
|
|
|
Some(Arc::new(RwLock::new(transaction_notifier)))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2021-12-29 15:12:01 -08:00
|
|
|
let (slot_status_observer, block_metadata_notifier): (
|
|
|
|
Option<SlotStatusObserver>,
|
|
|
|
Option<BlockMetadataNotifierLock>,
|
|
|
|
) = if account_data_notifications_enabled || transaction_notifications_enabled {
|
|
|
|
let slot_status_notifier = SlotStatusNotifierImpl::new(plugin_manager.clone());
|
|
|
|
let slot_status_notifier = Arc::new(RwLock::new(slot_status_notifier));
|
|
|
|
(
|
2021-11-23 09:55:53 -08:00
|
|
|
Some(SlotStatusObserver::new(
|
|
|
|
confirmed_bank_receiver,
|
|
|
|
slot_status_notifier,
|
2021-12-29 15:12:01 -08:00
|
|
|
)),
|
|
|
|
Some(Arc::new(RwLock::new(BlockMetadataNotifierImpl::new(
|
|
|
|
plugin_manager.clone(),
|
|
|
|
)))),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
(None, None)
|
|
|
|
};
|
2021-10-08 20:06:58 -07:00
|
|
|
|
2022-03-14 18:18:46 -07:00
|
|
|
info!("Started GeyserPluginService");
|
|
|
|
Ok(GeyserPluginService {
|
2021-10-08 20:06:58 -07:00
|
|
|
slot_status_observer,
|
|
|
|
plugin_manager,
|
|
|
|
accounts_update_notifier,
|
2021-11-23 09:55:53 -08:00
|
|
|
transaction_notifier,
|
2021-12-29 15:12:01 -08:00
|
|
|
block_metadata_notifier,
|
2021-10-08 20:06:58 -07:00
|
|
|
})
|
|
|
|
}
|
2021-09-30 14:26:17 -07:00
|
|
|
|
2021-10-08 20:06:58 -07:00
|
|
|
fn load_plugin(
|
2022-03-14 18:18:46 -07:00
|
|
|
plugin_manager: &mut GeyserPluginManager,
|
|
|
|
geyser_plugin_config_file: &Path,
|
|
|
|
) -> Result<(), GeyserPluginServiceError> {
|
|
|
|
let mut file = match File::open(geyser_plugin_config_file) {
|
2021-09-30 14:26:17 -07:00
|
|
|
Ok(file) => file,
|
|
|
|
Err(err) => {
|
2022-03-14 18:18:46 -07:00
|
|
|
return Err(GeyserPluginServiceError::CannotOpenConfigFile(format!(
|
2021-09-30 14:26:17 -07:00
|
|
|
"Failed to open the plugin config file {:?}, error: {:?}",
|
2022-03-14 18:18:46 -07:00
|
|
|
geyser_plugin_config_file, err
|
2021-09-30 14:26:17 -07:00
|
|
|
)));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut contents = String::new();
|
|
|
|
if let Err(err) = file.read_to_string(&mut contents) {
|
2022-03-14 18:18:46 -07:00
|
|
|
return Err(GeyserPluginServiceError::CannotReadConfigFile(format!(
|
2021-09-30 14:26:17 -07:00
|
|
|
"Failed to read the plugin config file {:?}, error: {:?}",
|
2022-03-14 18:18:46 -07:00
|
|
|
geyser_plugin_config_file, err
|
2021-09-30 14:26:17 -07:00
|
|
|
)));
|
|
|
|
}
|
|
|
|
|
2022-01-22 18:00:06 -08:00
|
|
|
let result: serde_json::Value = match json5::from_str(&contents) {
|
2021-09-30 14:26:17 -07:00
|
|
|
Ok(value) => value,
|
|
|
|
Err(err) => {
|
2022-03-14 18:18:46 -07:00
|
|
|
return Err(GeyserPluginServiceError::InvalidConfigFileFormat(format!(
|
|
|
|
"The config file {:?} is not in a valid Json5 format, error: {:?}",
|
|
|
|
geyser_plugin_config_file, err
|
|
|
|
)));
|
2021-09-30 14:26:17 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let libpath = result["libpath"]
|
|
|
|
.as_str()
|
2022-03-14 18:18:46 -07:00
|
|
|
.ok_or(GeyserPluginServiceError::LibPathNotSet)?;
|
2022-02-11 15:20:54 -08:00
|
|
|
let mut libpath = PathBuf::from(libpath);
|
|
|
|
if libpath.is_relative() {
|
2022-03-14 18:18:46 -07:00
|
|
|
let config_dir = geyser_plugin_config_file.parent().ok_or_else(|| {
|
|
|
|
GeyserPluginServiceError::CannotOpenConfigFile(format!(
|
2022-02-11 15:20:54 -08:00
|
|
|
"Failed to resolve parent of {:?}",
|
2022-03-14 18:18:46 -07:00
|
|
|
geyser_plugin_config_file,
|
2022-02-11 15:20:54 -08:00
|
|
|
))
|
|
|
|
})?;
|
|
|
|
libpath = config_dir.join(libpath);
|
|
|
|
}
|
|
|
|
|
2022-03-14 18:18:46 -07:00
|
|
|
let config_file = geyser_plugin_config_file
|
2021-09-30 14:26:17 -07:00
|
|
|
.as_os_str()
|
|
|
|
.to_str()
|
2022-03-14 18:18:46 -07:00
|
|
|
.ok_or(GeyserPluginServiceError::InvalidPluginPath)?;
|
2021-09-30 14:26:17 -07:00
|
|
|
|
|
|
|
unsafe {
|
2022-02-11 15:20:54 -08:00
|
|
|
let result = plugin_manager.load_plugin(libpath.to_str().unwrap(), config_file);
|
2021-09-30 14:26:17 -07:00
|
|
|
if let Err(err) = result {
|
|
|
|
let msg = format!(
|
|
|
|
"Failed to load the plugin library: {:?}, error: {:?}",
|
|
|
|
libpath, err
|
|
|
|
);
|
2022-03-14 18:18:46 -07:00
|
|
|
return Err(GeyserPluginServiceError::PluginLoadError(msg));
|
2021-09-30 14:26:17 -07:00
|
|
|
}
|
|
|
|
}
|
2021-10-08 20:06:58 -07:00
|
|
|
Ok(())
|
2021-09-30 14:26:17 -07:00
|
|
|
}
|
|
|
|
|
2021-11-17 17:11:38 -08:00
|
|
|
pub fn get_accounts_update_notifier(&self) -> Option<AccountsUpdateNotifier> {
|
2021-09-30 14:26:17 -07:00
|
|
|
self.accounts_update_notifier.clone()
|
|
|
|
}
|
|
|
|
|
2021-11-23 09:55:53 -08:00
|
|
|
pub fn get_transaction_notifier(&self) -> Option<TransactionNotifierLock> {
|
|
|
|
self.transaction_notifier.clone()
|
|
|
|
}
|
|
|
|
|
2021-12-29 15:12:01 -08:00
|
|
|
pub fn get_block_metadata_notifier(&self) -> Option<BlockMetadataNotifierLock> {
|
|
|
|
self.block_metadata_notifier.clone()
|
|
|
|
}
|
|
|
|
|
2021-11-17 17:11:38 -08:00
|
|
|
pub fn join(self) -> thread::Result<()> {
|
|
|
|
if let Some(mut slot_status_observer) = self.slot_status_observer {
|
|
|
|
slot_status_observer.join()?;
|
|
|
|
}
|
2021-09-30 14:26:17 -07:00
|
|
|
self.plugin_manager.write().unwrap().unload();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|