0.5.1-pre.002
This commit is contained in:
499
ks-lib/src/executor/api/execution.rs
Normal file
499
ks-lib/src/executor/api/execution.rs
Normal file
@@ -0,0 +1,499 @@
|
||||
// file: ks-lib/src/executor/api/execution.rs
|
||||
// version: 10
|
||||
|
||||
//! Typed execution plans, policies and result contracts.
|
||||
|
||||
use ts_rs::TS; // rust-rules: derive-import
|
||||
|
||||
/// Exact capability returned for one program operation.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[serde(tag = "status", rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionCapability.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionCapability {
|
||||
/// The operation is implemented by the executor.
|
||||
Supported {
|
||||
/// Stable operation code implemented by the executor.
|
||||
operation_code: std::string::String,
|
||||
},
|
||||
/// The operation is not implemented or is rejected by design.
|
||||
Unsupported {
|
||||
/// Stable reason code.
|
||||
reason_code: std::string::String,
|
||||
/// Human-readable reason.
|
||||
reason: std::string::String,
|
||||
},
|
||||
}
|
||||
|
||||
impl crate::ExApiExecutionCapability {
|
||||
/// Creates a supported capability value.
|
||||
pub fn supported(operation_code: impl std::convert::Into<std::string::String>) -> Self {
|
||||
return Self::Supported { operation_code: operation_code.into() };
|
||||
}
|
||||
|
||||
/// Creates an unsupported capability value.
|
||||
pub fn unsupported(
|
||||
reason_code: impl std::convert::Into<std::string::String>,
|
||||
reason: impl std::convert::Into<std::string::String>,
|
||||
) -> Self {
|
||||
return Self::Unsupported {
|
||||
reason_code: reason_code.into(),
|
||||
reason: reason.into(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns whether the capability is explicitly supported.
|
||||
pub fn is_supported(&self) -> bool {
|
||||
return matches!(self, Self::Supported { operation_code: _ });
|
||||
}
|
||||
}
|
||||
|
||||
/// Solana cluster expected by an execution plan.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionCluster.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionCluster {
|
||||
/// Local validator cluster.
|
||||
Localnet,
|
||||
/// Public development cluster.
|
||||
Devnet,
|
||||
/// Public test cluster.
|
||||
Testnet,
|
||||
/// Public production cluster.
|
||||
///
|
||||
/// RPC URLs and CLI aliases may still use `mainnet-beta`.
|
||||
Mainnet,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
enum ExecutionClusterWire {
|
||||
Localnet,
|
||||
Devnet,
|
||||
Testnet,
|
||||
#[serde(alias = "mainnet_beta")]
|
||||
Mainnet,
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for crate::ExApiExecutionCluster {
|
||||
fn deserialize<Deserializer>(
|
||||
deserializer: Deserializer,
|
||||
) -> std::result::Result<Self, Deserializer::Error>
|
||||
where
|
||||
Deserializer: serde::Deserializer<'de>,
|
||||
{
|
||||
let wire = match <ExecutionClusterWire as serde::Deserialize>::deserialize(deserializer) {
|
||||
std::result::Result::Ok(wire) => wire,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
return std::result::Result::Ok(match wire {
|
||||
ExecutionClusterWire::Localnet => Self::Localnet,
|
||||
ExecutionClusterWire::Devnet => Self::Devnet,
|
||||
ExecutionClusterWire::Testnet => Self::Testnet,
|
||||
ExecutionClusterWire::Mainnet => Self::Mainnet,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Cluster restrictions attached to an execution plan.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionClusterPolicy.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionClusterPolicy {
|
||||
/// Cluster that the RPC endpoint must report.
|
||||
pub expected_cluster: crate::ExApiExecutionCluster,
|
||||
/// Whether production execution may proceed after all other checks.
|
||||
pub allow_mainnet: bool,
|
||||
/// Whether the operator explicitly confirmed this production execution.
|
||||
pub mainnet_confirmation: bool,
|
||||
}
|
||||
|
||||
impl std::default::Default for crate::ExApiExecutionClusterPolicy {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
expected_cluster: crate::ExApiExecutionCluster::Devnet,
|
||||
allow_mainnet: false,
|
||||
mainnet_confirmation: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Simulation requirement attached to an execution plan.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionSimulationPolicy.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionSimulationPolicy {
|
||||
/// Simulation must succeed before signing or sending.
|
||||
Required,
|
||||
/// Simulation is not required. Safety policy rejects this mode by default.
|
||||
Optional,
|
||||
}
|
||||
|
||||
/// Blockhash source required when a transaction is assembled.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionBlockhashKind.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionBlockhashKind {
|
||||
/// Fetch a recent blockhash and enforce a bounded age.
|
||||
Latest,
|
||||
/// Use a durable nonce account and authority.
|
||||
DurableNonce,
|
||||
}
|
||||
|
||||
/// Blockhash or durable nonce policy attached to an execution plan.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionBlockhashPolicy.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionBlockhashPolicy {
|
||||
/// Selected blockhash source.
|
||||
pub kind: crate::ExApiExecutionBlockhashKind,
|
||||
/// Maximum accepted age for a recent blockhash, in slots.
|
||||
pub max_age_slots: std::option::Option<u64>,
|
||||
/// Durable nonce account when `kind` is `DurableNonce`.
|
||||
pub nonce_account: std::option::Option<crate::MdPubkey>,
|
||||
/// Durable nonce authority when `kind` is `DurableNonce`.
|
||||
pub nonce_authority: std::option::Option<crate::MdPubkey>,
|
||||
}
|
||||
|
||||
impl std::default::Default for crate::ExApiExecutionBlockhashPolicy {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
kind: crate::ExApiExecutionBlockhashKind::Latest,
|
||||
max_age_slots: std::option::Option::Some(150),
|
||||
nonce_account: std::option::Option::None,
|
||||
nonce_authority: std::option::Option::None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Explicit cost ceilings attached to an execution plan.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionCostLimit.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionCostLimit {
|
||||
/// Maximum lamports that operation instructions may transfer or lock.
|
||||
pub max_spend_lamports: std::option::Option<u64>,
|
||||
/// Maximum total transaction fee accepted after simulation.
|
||||
pub max_fee_lamports: std::option::Option<u64>,
|
||||
/// Maximum compute-unit price accepted, in micro-lamports per compute unit.
|
||||
pub max_compute_unit_price_micro_lamports: std::option::Option<u64>,
|
||||
}
|
||||
|
||||
impl std::default::Default for crate::ExApiExecutionCostLimit {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
max_spend_lamports: std::option::Option::None,
|
||||
max_fee_lamports: std::option::Option::None,
|
||||
max_compute_unit_price_micro_lamports: std::option::Option::None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Post-execution replay validation policy.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/PostExecutionValidationPolicy.ts"
|
||||
)]
|
||||
pub struct ExApiPostExecutionValidationPolicy {
|
||||
/// Whether the sent signature must be inserted into canonical storage.
|
||||
pub canonical_insert_required: bool,
|
||||
/// Whether core extraction must complete.
|
||||
pub core_extraction_required: bool,
|
||||
/// Whether contextual decode replay must complete.
|
||||
pub decode_replay_required: bool,
|
||||
/// Whether compatible materializers must run.
|
||||
pub materialization_required: bool,
|
||||
}
|
||||
|
||||
impl std::default::Default for crate::ExApiPostExecutionValidationPolicy {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
canonical_insert_required: true,
|
||||
core_extraction_required: true,
|
||||
decode_replay_required: true,
|
||||
materialization_required: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Conservative policy carried from intent creation to transaction assembly.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionPolicy.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionPolicy {
|
||||
/// Cluster restrictions.
|
||||
pub cluster: crate::ExApiExecutionClusterPolicy,
|
||||
/// Simulation requirement.
|
||||
pub simulation: crate::ExApiExecutionSimulationPolicy,
|
||||
/// Blockhash source restrictions.
|
||||
pub blockhash: crate::ExApiExecutionBlockhashPolicy,
|
||||
/// Explicit operation and fee ceilings.
|
||||
pub cost_limit: crate::ExApiExecutionCostLimit,
|
||||
/// Public keys authorized to sign this plan.
|
||||
pub authorized_signers: std::vec::Vec<crate::MdPubkey>,
|
||||
/// Whether the operation is restricted to plan construction and simulation.
|
||||
pub dry_run: bool,
|
||||
/// Required post-execution validation steps.
|
||||
pub post_execution_validation: crate::ExApiPostExecutionValidationPolicy,
|
||||
}
|
||||
|
||||
impl std::default::Default for crate::ExApiExecutionPolicy {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
cluster: crate::ExApiExecutionClusterPolicy::default(),
|
||||
simulation: crate::ExApiExecutionSimulationPolicy::Required,
|
||||
blockhash: crate::ExApiExecutionBlockhashPolicy::default(),
|
||||
cost_limit: crate::ExApiExecutionCostLimit::default(),
|
||||
authorized_signers: std::vec::Vec::new(),
|
||||
dry_run: true,
|
||||
post_execution_validation: crate::ExApiPostExecutionValidationPolicy::default(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// One account required by a planned instruction.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/PlannedAccount.ts"
|
||||
)]
|
||||
pub struct ExApiPlannedAccount {
|
||||
/// Account public key.
|
||||
pub pubkey: crate::MdPubkey,
|
||||
/// Whether the account must sign the transaction.
|
||||
pub is_signer: bool,
|
||||
/// Whether the account must be writable.
|
||||
pub is_writable: bool,
|
||||
}
|
||||
|
||||
/// One fully encoded instruction in an execution plan.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/PlannedInstruction.ts"
|
||||
)]
|
||||
pub struct ExApiPlannedInstruction {
|
||||
/// Target program id.
|
||||
pub program_id: crate::MdProgramId,
|
||||
/// Stable operation code represented by the instruction.
|
||||
pub operation_code: std::string::String,
|
||||
/// Ordered account metadata.
|
||||
pub accounts: std::vec::Vec<crate::ExApiPlannedAccount>,
|
||||
/// Exact encoded instruction payload.
|
||||
pub data: std::vec::Vec<u8>,
|
||||
}
|
||||
|
||||
/// Signer required before transaction assembly.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/RequiredSigner.ts"
|
||||
)]
|
||||
pub struct ExApiRequiredSigner {
|
||||
/// Signer public key.
|
||||
pub pubkey: crate::MdPubkey,
|
||||
/// Stable signer role such as `fee_payer`, `funding_account` or `new_account`.
|
||||
pub role: std::string::String,
|
||||
}
|
||||
|
||||
/// Typed execution plan produced before transaction assembly.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/PreparedExecutionPlan.ts"
|
||||
)]
|
||||
pub struct ExApiPreparedExecutionPlan {
|
||||
/// Stable executor crate name.
|
||||
pub executor_name: std::string::String,
|
||||
/// Executor package version.
|
||||
pub executor_version: std::string::String,
|
||||
/// Caller-provided intent identifier.
|
||||
pub intent_id: std::string::String,
|
||||
/// Stable operation code.
|
||||
pub operation_code: std::string::String,
|
||||
/// Transaction fee payer.
|
||||
pub fee_payer: crate::MdPubkey,
|
||||
/// Ordered instructions to place in the transaction message.
|
||||
pub instructions: std::vec::Vec<crate::ExApiPlannedInstruction>,
|
||||
/// Deduplicated signers required by the fee payer and instruction metas.
|
||||
pub required_signers: std::vec::Vec<crate::ExApiRequiredSigner>,
|
||||
/// Explicit policy to evaluate before simulation, signing and sending.
|
||||
pub policy: crate::ExApiExecutionPolicy,
|
||||
/// Lamports explicitly transferred or locked by planned instructions.
|
||||
pub requested_spend_lamports: u64,
|
||||
/// Requested compute-unit price, when present.
|
||||
pub requested_compute_unit_price_micro_lamports: std::option::Option<u64>,
|
||||
}
|
||||
|
||||
/// Result returned by a transaction simulation adapter.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionSimulationResult.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionSimulationResult {
|
||||
/// Whether an RPC simulation call was actually performed.
|
||||
pub simulated: bool,
|
||||
/// Whether the simulated transaction completed successfully.
|
||||
pub success: bool,
|
||||
/// Cluster reported by the simulation adapter.
|
||||
pub cluster: crate::ExApiExecutionCluster,
|
||||
/// Blockhash source used by the simulated transaction.
|
||||
pub blockhash_kind: crate::ExApiExecutionBlockhashKind,
|
||||
/// Observed recent blockhash age, in slots.
|
||||
pub blockhash_age_slots: std::option::Option<u64>,
|
||||
/// Replacement blockhash returned by the node, if replacement was requested.
|
||||
#[serde(default)]
|
||||
pub replacement_blockhash: std::option::Option<std::string::String>,
|
||||
/// Last valid block height associated with the replacement blockhash.
|
||||
#[serde(default)]
|
||||
pub replacement_last_valid_block_height: std::option::Option<u64>,
|
||||
/// Durable nonce account used by the simulated transaction.
|
||||
pub nonce_account: std::option::Option<crate::MdPubkey>,
|
||||
/// Durable nonce authority used by the simulated transaction.
|
||||
pub nonce_authority: std::option::Option<crate::MdPubkey>,
|
||||
/// Compute units consumed when reported by the RPC endpoint.
|
||||
pub units_consumed: std::option::Option<u64>,
|
||||
/// Estimated transaction fee in lamports when available.
|
||||
pub estimated_fee_lamports: std::option::Option<u64>,
|
||||
/// Simulation logs in runtime order.
|
||||
pub logs: std::vec::Vec<std::string::String>,
|
||||
/// Program return data retained as provider-neutral JSON when reported.
|
||||
#[serde(default)]
|
||||
pub return_data: std::option::Option<serde_json::Value>,
|
||||
/// Stable or provider error text when simulation failed.
|
||||
pub error: std::option::Option<std::string::String>,
|
||||
}
|
||||
|
||||
/// Result returned after an adapter submits a signed transaction.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionSendResult.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionSendResult {
|
||||
/// Cluster used for submission.
|
||||
pub cluster: crate::ExApiExecutionCluster,
|
||||
/// Signature returned by the RPC endpoint.
|
||||
pub signature: crate::MdSignature,
|
||||
/// Whether submission was accepted by the RPC endpoint.
|
||||
pub submitted: bool,
|
||||
}
|
||||
|
||||
/// Confirmation state returned by an execution confirmation adapter.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionConfirmationStatus.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionConfirmationStatus {
|
||||
/// The transaction was observed at processed commitment.
|
||||
Processed,
|
||||
/// The transaction reached confirmed commitment.
|
||||
Confirmed,
|
||||
/// The transaction reached finalized commitment.
|
||||
Finalized,
|
||||
/// The transaction was confirmed with a runtime error.
|
||||
Failed,
|
||||
/// The transaction was not confirmed before its blockhash expired.
|
||||
Expired,
|
||||
/// The bounded confirmation poll ended before reaching the requested commitment.
|
||||
TimedOut,
|
||||
}
|
||||
|
||||
/// Result returned after waiting for transaction confirmation.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/ExecutionConfirmationResult.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionConfirmationResult {
|
||||
/// Cluster queried for confirmation.
|
||||
pub cluster: crate::ExApiExecutionCluster,
|
||||
/// Submitted transaction signature.
|
||||
pub signature: crate::MdSignature,
|
||||
/// Highest confirmation state reached.
|
||||
pub status: crate::ExApiExecutionConfirmationStatus,
|
||||
/// Slot that reported the transaction when available.
|
||||
pub slot: std::option::Option<u64>,
|
||||
/// Number of status polling attempts performed.
|
||||
pub attempts: u32,
|
||||
/// Last block height observed while checking recent-blockhash expiration.
|
||||
pub last_observed_block_height: std::option::Option<u64>,
|
||||
/// Stable or provider error text when confirmation failed.
|
||||
pub error: std::option::Option<std::string::String>,
|
||||
}
|
||||
|
||||
/// Diagnostic produced by post-execution canonical replay validation.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/execution/PostExecutionDiagnostic.ts"
|
||||
)]
|
||||
pub struct ExApiPostExecutionDiagnostic {
|
||||
/// Executed transaction signature.
|
||||
pub signature: crate::MdSignature,
|
||||
/// Whether canonical insertion completed.
|
||||
pub canonical_inserted: bool,
|
||||
/// Whether core extraction completed.
|
||||
pub core_extracted: bool,
|
||||
/// Whether contextual decode replay completed.
|
||||
pub decode_replayed: bool,
|
||||
/// Whether requested materialization completed.
|
||||
pub materialized: bool,
|
||||
/// Diagnostic messages from orchestration layers.
|
||||
pub diagnostics: std::vec::Vec<std::string::String>,
|
||||
}
|
||||
|
||||
/// Contract implemented by executors that expose typed intents and exact plans.
|
||||
pub trait ExApiTypedInstructionExecutor {
|
||||
/// Protocol-specific typed intent.
|
||||
type Intent;
|
||||
|
||||
/// Returns the exact capability for one program and operation code.
|
||||
fn capability(
|
||||
&self,
|
||||
program_id: &crate::MdProgramId,
|
||||
operation_code: &str,
|
||||
) -> crate::ExApiExecutionCapability;
|
||||
|
||||
/// Builds a typed execution plan without signing, sending or performing I/O.
|
||||
fn build_prepared_plan(
|
||||
&self,
|
||||
intent: &Self::Intent,
|
||||
) -> ks_core::Result<crate::ExApiPreparedExecutionPlan>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn mainnet_cluster_serializes_with_current_name() {
|
||||
let serialized = serde_json::to_string(&crate::ExApiExecutionCluster::Mainnet)
|
||||
.unwrap_or_else(|error| panic!("unexpected serialization error: {error}"));
|
||||
assert_eq!(serialized, "\"mainnet\"");
|
||||
let legacy = serde_json::from_str::<crate::ExApiExecutionCluster>("\"mainnet_beta\"")
|
||||
.unwrap_or_else(|error| panic!("unexpected deserialization error: {error}"));
|
||||
assert_eq!(legacy, crate::ExApiExecutionCluster::Mainnet);
|
||||
}
|
||||
}
|
||||
109
ks-lib/src/executor/api/executor.rs
Normal file
109
ks-lib/src/executor/api/executor.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
// file: ks-lib/src/executor/api/executor.rs
|
||||
// version: 5
|
||||
|
||||
//! Shared execution contract and neutral request models.
|
||||
|
||||
use ts_rs::TS; // rust-rules: derive-import
|
||||
|
||||
/// Support level returned by an executor for a requested operation.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/executor/ExecutionSupport.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionSupport {
|
||||
/// The executor cannot handle the request.
|
||||
No,
|
||||
/// The executor may handle the request after account and payload validation.
|
||||
Maybe,
|
||||
/// The executor explicitly supports the request.
|
||||
Yes,
|
||||
}
|
||||
|
||||
/// Generic request used before protocol-specific execution models are introduced.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/executor/ExecutionRequest.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionRequest {
|
||||
/// Target program id.
|
||||
pub program_id: crate::MdProgramId,
|
||||
/// Stable operation code such as buy, sell, transfer or route.
|
||||
pub operation_code: std::string::String,
|
||||
/// Serialized JSON payload reserved for protocol-specific arguments.
|
||||
pub payload_json: std::string::String,
|
||||
}
|
||||
|
||||
/// Neutral execution plan placeholder produced by executor crates.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/ks_lib/executor/api/executor/ExecutionPlan.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionPlan {
|
||||
/// Stable executor crate name.
|
||||
pub executor_name: std::string::String,
|
||||
/// Number of instructions that would be produced by the final implementation.
|
||||
pub instruction_count: usize,
|
||||
/// Serialized JSON payload reserved for future instruction data and account metadata.
|
||||
pub payload_json: std::string::String,
|
||||
}
|
||||
|
||||
/// Serializes a JSON payload to its compact string representation.
|
||||
pub fn executor_api_serialize_payload_json(
|
||||
value: &serde_json::Value,
|
||||
) -> ks_core::Result<std::string::String> {
|
||||
return match serde_json::to_string(value) {
|
||||
std::result::Result::Ok(serialized) => std::result::Result::Ok(serialized),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_payload_json_serialize_failed",
|
||||
error.to_string(),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
/// Serializes a JSON payload to its pretty string representation.
|
||||
pub fn executor_api_serialize_payload_json_pretty(
|
||||
value: &serde_json::Value,
|
||||
) -> ks_core::Result<std::string::String> {
|
||||
return match serde_json::to_string_pretty(value) {
|
||||
std::result::Result::Ok(serialized) => std::result::Result::Ok(serialized),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
|
||||
"execution_payload_json_pretty_serialize_failed",
|
||||
error.to_string(),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
/// Common contract implemented by all execution crates.
|
||||
pub trait ExApiInstructionExecutor {
|
||||
/// Returns the stable executor name.
|
||||
fn executor_name(&self) -> &'static str;
|
||||
|
||||
/// Returns the executor version.
|
||||
fn executor_version(&self) -> &'static str;
|
||||
|
||||
/// Returns the program ids handled by this executor.
|
||||
fn program_ids(&self) -> &'static [&'static str];
|
||||
|
||||
/// Tests whether this executor owns a program id.
|
||||
fn handles_program_id(&self, program_id: &crate::MdProgramId) -> bool {
|
||||
return self
|
||||
.program_ids()
|
||||
.iter()
|
||||
.any(|candidate| return *candidate == program_id.0.as_str());
|
||||
}
|
||||
|
||||
/// Tests whether this executor supports a request.
|
||||
fn supports_request(
|
||||
&self,
|
||||
request: &crate::ExApiExecutionRequest,
|
||||
) -> crate::ExApiExecutionSupport;
|
||||
|
||||
/// Builds a neutral execution plan placeholder.
|
||||
fn build_plan(
|
||||
&self,
|
||||
request: &crate::ExApiExecutionRequest,
|
||||
) -> ks_core::Result<crate::ExApiExecutionPlan>;
|
||||
}
|
||||
Reference in New Issue
Block a user