0.1.0
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# file: kb_execution_api/Cargo.toml
|
||||
# version: 2
|
||||
|
||||
[package]
|
||||
name = "kb_execution_api"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
kb_core = { path = "../kb_core" }
|
||||
kb_model = { path = "../kb_model" }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
ts-rs.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
101
migration/khadhroony-bot2-reference/kb_execution_api/README.md
Normal file
101
migration/khadhroony-bot2-reference/kb_execution_api/README.md
Normal file
@@ -0,0 +1,101 @@
|
||||
<!-- file: kb_execution_api/README.md -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# kb_execution_api
|
||||
|
||||
Cette crate définit les contrats communs de la couche d’exécution. Elle ne dépend ni du wallet, ni du RPC, ni du stockage, ni des décodeurs et ne construit aucune instruction Solana.
|
||||
|
||||
## API publique
|
||||
|
||||
### Capacités et traits
|
||||
|
||||
| Export | Usage |
|
||||
|-----------------------------------------|----------------------------------------------------------------------------------------------------------------------------|
|
||||
| `ExecutionCapability` | Réponse exacte `Supported { operation_code }` ou `Unsupported { reason_code, reason }` pour un couple programme/opération. |
|
||||
| `ExecutionCapability::supported(...)` | Construit une capacité supportée avec un code stable. |
|
||||
| `ExecutionCapability::unsupported(...)` | Construit un refus documenté avec code et message. |
|
||||
| `ExecutionCapability::is_supported()` | Teste la capacité sans perdre le diagnostic du variant complet. |
|
||||
| `TypedInstructionExecutor` | Contrat actuel : expose `capability(...)` et `build_prepared_plan(...)` sans I/O, signature ou envoi. |
|
||||
| `InstructionExecutor` | Pont historique fondé sur `ExecutionRequest`/`ExecutionPlan`; il reste disponible pour les crates réservées. |
|
||||
| `ExecutionSupport` | Résultat historique `No`, `Maybe` ou `Yes`; les exécuteurs opérationnels doivent éviter `Maybe`. |
|
||||
|
||||
### Politiques
|
||||
|
||||
| Export | Usage |
|
||||
|---------------------------------|-----------------------------------------------------------------------------------------------------------|
|
||||
| `ExecutionPolicy` | Agrège cluster, simulation, blockhash/nonce, plafonds, signataires autorisés, dry-run et post-validation. |
|
||||
| `ExecutionCluster` | Cluster attendu : Localnet, Devnet, Testnet ou Mainnet. |
|
||||
| `ExecutionClusterPolicy` | Autorisation du cluster et double confirmation Mainnet. |
|
||||
| `ExecutionSimulationPolicy` | Indique si la simulation est obligatoire. |
|
||||
| `ExecutionBlockhashKind` | Sélectionne un recent blockhash ou un durable nonce. |
|
||||
| `ExecutionBlockhashPolicy` | Porte l’âge maximal du blockhash ou le compte et l’autorité nonce. |
|
||||
| `ExecutionCostLimit` | Plafonds de dépense, frais totaux et prix par compute unit. |
|
||||
| `PostExecutionValidationPolicy` | Étapes exigées après confirmation : canonical insert, core extraction, decode replay et matérialisation. |
|
||||
|
||||
Tous les types de politique implémentent des valeurs par défaut conservatrices : Devnet, simulation obligatoire, recent blockhash borné, dry-run actif et Mainnet désactivé.
|
||||
|
||||
### Plan préparé
|
||||
|
||||
| Export | Usage |
|
||||
|-------------------------|-------------------------------------------------------------------------------------|
|
||||
| `PreparedExecutionPlan` | Contrat immutable transmis de l’exécuteur à la sécurité puis à l’assembleur Solana. |
|
||||
| `PlannedInstruction` | Program ID, code d’opération, comptes ordonnés et payload exact. |
|
||||
| `PlannedAccount` | Public key et flags signer/writable d’un compte d’instruction. |
|
||||
| `RequiredSigner` | Public key et rôle stable d’un signataire requis. |
|
||||
|
||||
Un plan contient également l’exécuteur/version, l’identifiant d’intent, le fee payer, la politique, les lamports dépensés ou verrouillés et le prix Compute Budget demandé.
|
||||
|
||||
### Résultats d’orchestration
|
||||
|
||||
| Export | Usage |
|
||||
|-------------------------------|-------------------------------------------------------------------------------------------------------------------|
|
||||
| `ExecutionSimulationResult` | Preuve provider-neutral d’une simulation, avec contexte cluster/blockhash, frais, unités, logs et erreur runtime. |
|
||||
| `ExecutionSendResult` | Signature acceptée par le RPC et slot de soumission éventuel. |
|
||||
| `ExecutionConfirmationStatus` | État final ou intermédiaire de confirmation. |
|
||||
| `ExecutionConfirmationResult` | Résultat borné des polls de confirmation. |
|
||||
| `PostExecutionDiagnostic` | Résumé des étapes canonical/core/decode/materialization après exécution. |
|
||||
|
||||
### Compatibilité et helpers JSON
|
||||
|
||||
| Export | Usage |
|
||||
|--------------------------------------|------------------------------------------------------------------------|
|
||||
| `ExecutionRequest` | Requête historique `program_id + operation_code + payload_json`. |
|
||||
| `ExecutionPlan` | Plan historique sérialisé, sans garantie d’être directement envoyable. |
|
||||
| `serialize_payload_json(...)` | Sérialise un `serde_json::Value` compact avec `kb_core::Error`. |
|
||||
| `serialize_payload_json_pretty(...)` | Sérialise le même payload en forme lisible. |
|
||||
|
||||
## Exemple d’implémentation d’un exécuteur
|
||||
|
||||
```rust
|
||||
impl kb_execution_api::TypedInstructionExecutor for MyExecutor {
|
||||
type Intent = MyIntent;
|
||||
|
||||
fn capability(
|
||||
&self,
|
||||
program_id: &kb_model::ProgramId,
|
||||
operation_code: &str,
|
||||
) -> kb_execution_api::ExecutionCapability {
|
||||
// Return an exact Supported or Unsupported result.
|
||||
}
|
||||
|
||||
fn build_prepared_plan(
|
||||
&self,
|
||||
intent: &Self::Intent,
|
||||
) -> kb_core::Result<kb_execution_api::PreparedExecutionPlan> {
|
||||
// Validate and encode only. Do not access RPC or sign here.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Frontières
|
||||
|
||||
`kb_execution_api` ne décide pas qu’un plan est sûr, ne compile pas de message Solana et ne contacte aucun endpoint. Le flux attendu est :
|
||||
|
||||
```text
|
||||
executor intent
|
||||
-> PreparedExecutionPlan
|
||||
-> kb_execution_safety
|
||||
-> kb_execution_solana
|
||||
-> kb_rpc
|
||||
-> post-execution orchestration
|
||||
```
|
||||
@@ -0,0 +1,496 @@
|
||||
// file: kb_execution_api/src/execution.rs
|
||||
// version: 7
|
||||
|
||||
//! 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/kb_execution_api/execution/ExecutionCapability.ts"
|
||||
)]
|
||||
pub enum ExecutionCapability {
|
||||
/// 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::ExecutionCapability {
|
||||
/// 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/kb_execution_api/execution/ExecutionCluster.ts"
|
||||
)]
|
||||
pub enum ExecutionCluster {
|
||||
/// 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::ExecutionCluster {
|
||||
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/kb_execution_api/execution/ExecutionClusterPolicy.ts"
|
||||
)]
|
||||
pub struct ExecutionClusterPolicy {
|
||||
/// Cluster that the RPC endpoint must report.
|
||||
pub expected_cluster: crate::ExecutionCluster,
|
||||
/// 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::ExecutionClusterPolicy {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
expected_cluster: crate::ExecutionCluster::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/kb_execution_api/execution/ExecutionSimulationPolicy.ts"
|
||||
)]
|
||||
pub enum ExecutionSimulationPolicy {
|
||||
/// 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/kb_execution_api/execution/ExecutionBlockhashKind.ts"
|
||||
)]
|
||||
pub enum ExecutionBlockhashKind {
|
||||
/// 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/kb_execution_api/execution/ExecutionBlockhashPolicy.ts"
|
||||
)]
|
||||
pub struct ExecutionBlockhashPolicy {
|
||||
/// Selected blockhash source.
|
||||
pub kind: crate::ExecutionBlockhashKind,
|
||||
/// 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<kb_model::Pubkey>,
|
||||
/// Durable nonce authority when `kind` is `DurableNonce`.
|
||||
pub nonce_authority: std::option::Option<kb_model::Pubkey>,
|
||||
}
|
||||
|
||||
impl std::default::Default for crate::ExecutionBlockhashPolicy {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
kind: crate::ExecutionBlockhashKind::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/kb_execution_api/execution/ExecutionCostLimit.ts"
|
||||
)]
|
||||
pub struct ExecutionCostLimit {
|
||||
/// 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::ExecutionCostLimit {
|
||||
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/kb_execution_api/execution/PostExecutionValidationPolicy.ts"
|
||||
)]
|
||||
pub struct PostExecutionValidationPolicy {
|
||||
/// 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::PostExecutionValidationPolicy {
|
||||
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/kb_execution_api/execution/ExecutionPolicy.ts"
|
||||
)]
|
||||
pub struct ExecutionPolicy {
|
||||
/// Cluster restrictions.
|
||||
pub cluster: crate::ExecutionClusterPolicy,
|
||||
/// Simulation requirement.
|
||||
pub simulation: crate::ExecutionSimulationPolicy,
|
||||
/// Blockhash source restrictions.
|
||||
pub blockhash: crate::ExecutionBlockhashPolicy,
|
||||
/// Explicit operation and fee ceilings.
|
||||
pub cost_limit: crate::ExecutionCostLimit,
|
||||
/// Public keys authorized to sign this plan.
|
||||
pub authorized_signers: std::vec::Vec<kb_model::Pubkey>,
|
||||
/// Whether the operation is restricted to plan construction and simulation.
|
||||
pub dry_run: bool,
|
||||
/// Required post-execution validation steps.
|
||||
pub post_execution_validation: crate::PostExecutionValidationPolicy,
|
||||
}
|
||||
|
||||
impl std::default::Default for crate::ExecutionPolicy {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
cluster: crate::ExecutionClusterPolicy::default(),
|
||||
simulation: crate::ExecutionSimulationPolicy::Required,
|
||||
blockhash: crate::ExecutionBlockhashPolicy::default(),
|
||||
cost_limit: crate::ExecutionCostLimit::default(),
|
||||
authorized_signers: std::vec::Vec::new(),
|
||||
dry_run: true,
|
||||
post_execution_validation: crate::PostExecutionValidationPolicy::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/kb_execution_api/execution/PlannedAccount.ts"
|
||||
)]
|
||||
pub struct PlannedAccount {
|
||||
/// Account public key.
|
||||
pub pubkey: kb_model::Pubkey,
|
||||
/// 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/kb_execution_api/execution/PlannedInstruction.ts"
|
||||
)]
|
||||
pub struct PlannedInstruction {
|
||||
/// Target program id.
|
||||
pub program_id: kb_model::ProgramId,
|
||||
/// Stable operation code represented by the instruction.
|
||||
pub operation_code: std::string::String,
|
||||
/// Ordered account metadata.
|
||||
pub accounts: std::vec::Vec<crate::PlannedAccount>,
|
||||
/// 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/kb_execution_api/execution/RequiredSigner.ts"
|
||||
)]
|
||||
pub struct RequiredSigner {
|
||||
/// Signer public key.
|
||||
pub pubkey: kb_model::Pubkey,
|
||||
/// 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/kb_execution_api/execution/PreparedExecutionPlan.ts"
|
||||
)]
|
||||
pub struct PreparedExecutionPlan {
|
||||
/// 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: kb_model::Pubkey,
|
||||
/// Ordered instructions to place in the transaction message.
|
||||
pub instructions: std::vec::Vec<crate::PlannedInstruction>,
|
||||
/// Deduplicated signers required by the fee payer and instruction metas.
|
||||
pub required_signers: std::vec::Vec<crate::RequiredSigner>,
|
||||
/// Explicit policy to evaluate before simulation, signing and sending.
|
||||
pub policy: crate::ExecutionPolicy,
|
||||
/// 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/kb_execution_api/execution/ExecutionSimulationResult.ts"
|
||||
)]
|
||||
pub struct ExecutionSimulationResult {
|
||||
/// 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::ExecutionCluster,
|
||||
/// Blockhash source used by the simulated transaction.
|
||||
pub blockhash_kind: crate::ExecutionBlockhashKind,
|
||||
/// 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<kb_model::Pubkey>,
|
||||
/// Durable nonce authority used by the simulated transaction.
|
||||
pub nonce_authority: std::option::Option<kb_model::Pubkey>,
|
||||
/// 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>,
|
||||
/// 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/kb_execution_api/execution/ExecutionSendResult.ts"
|
||||
)]
|
||||
pub struct ExecutionSendResult {
|
||||
/// Cluster used for submission.
|
||||
pub cluster: crate::ExecutionCluster,
|
||||
/// Signature returned by the RPC endpoint.
|
||||
pub signature: kb_model::Signature,
|
||||
/// 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/kb_execution_api/execution/ExecutionConfirmationStatus.ts"
|
||||
)]
|
||||
pub enum ExecutionConfirmationStatus {
|
||||
/// 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/kb_execution_api/execution/ExecutionConfirmationResult.ts"
|
||||
)]
|
||||
pub struct ExecutionConfirmationResult {
|
||||
/// Cluster queried for confirmation.
|
||||
pub cluster: crate::ExecutionCluster,
|
||||
/// Submitted transaction signature.
|
||||
pub signature: kb_model::Signature,
|
||||
/// Highest confirmation state reached.
|
||||
pub status: crate::ExecutionConfirmationStatus,
|
||||
/// 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/kb_execution_api/execution/PostExecutionDiagnostic.ts"
|
||||
)]
|
||||
pub struct PostExecutionDiagnostic {
|
||||
/// Executed transaction signature.
|
||||
pub signature: kb_model::Signature,
|
||||
/// 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 TypedInstructionExecutor {
|
||||
/// Protocol-specific typed intent.
|
||||
type Intent;
|
||||
|
||||
/// Returns the exact capability for one program and operation code.
|
||||
fn capability(
|
||||
&self,
|
||||
program_id: &kb_model::ProgramId,
|
||||
operation_code: &str,
|
||||
) -> crate::ExecutionCapability;
|
||||
|
||||
/// Builds a typed execution plan without signing, sending or performing I/O.
|
||||
fn build_prepared_plan(
|
||||
&self,
|
||||
intent: &Self::Intent,
|
||||
) -> kb_core::Result<crate::PreparedExecutionPlan>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn mainnet_cluster_serializes_with_current_name() {
|
||||
let serialized = serde_json::to_string(&crate::ExecutionCluster::Mainnet)
|
||||
.unwrap_or_else(|error| panic!("unexpected serialization error: {error}"));
|
||||
assert_eq!(serialized, "\"mainnet\"");
|
||||
let legacy = serde_json::from_str::<crate::ExecutionCluster>("\"mainnet_beta\"")
|
||||
.unwrap_or_else(|error| panic!("unexpected deserialization error: {error}"));
|
||||
assert_eq!(legacy, crate::ExecutionCluster::Mainnet);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
// file: kb_execution_api/src/executor.rs
|
||||
// version: 3
|
||||
|
||||
//! 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/kb_execution_api/executor/ExecutionSupport.ts"
|
||||
)]
|
||||
pub enum ExecutionSupport {
|
||||
/// 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/kb_execution_api/executor/ExecutionRequest.ts"
|
||||
)]
|
||||
pub struct ExecutionRequest {
|
||||
/// Target program id.
|
||||
pub program_id: kb_model::ProgramId,
|
||||
/// 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/kb_execution_api/executor/ExecutionPlan.ts"
|
||||
)]
|
||||
pub struct ExecutionPlan {
|
||||
/// 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 serialize_payload_json(value: &serde_json::Value) -> kb_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(kb_core::Error::new(
|
||||
"execution_payload_json_serialize_failed",
|
||||
error.to_string(),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
/// Serializes a JSON payload to its pretty string representation.
|
||||
pub fn serialize_payload_json_pretty(
|
||||
value: &serde_json::Value,
|
||||
) -> kb_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(kb_core::Error::new(
|
||||
"execution_payload_json_pretty_serialize_failed",
|
||||
error.to_string(),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
/// Common contract implemented by all execution crates.
|
||||
pub trait InstructionExecutor {
|
||||
/// 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: &kb_model::ProgramId) -> 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::ExecutionRequest) -> crate::ExecutionSupport;
|
||||
|
||||
/// Builds a neutral execution plan placeholder.
|
||||
fn build_plan(
|
||||
&self,
|
||||
request: &crate::ExecutionRequest,
|
||||
) -> kb_core::Result<crate::ExecutionPlan>;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// file: kb_execution_api/src/lib.rs
|
||||
// version: 2
|
||||
|
||||
//! Execution API contract shared by all executor crates.
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
mod execution;
|
||||
mod executor;
|
||||
|
||||
/// Exposes the blockhash policy kind.
|
||||
pub use crate::execution::ExecutionBlockhashKind;
|
||||
/// Exposes the blockhash policy.
|
||||
pub use crate::execution::ExecutionBlockhashPolicy;
|
||||
/// Exposes the exact execution capability result.
|
||||
pub use crate::execution::ExecutionCapability;
|
||||
/// Exposes supported Solana clusters.
|
||||
pub use crate::execution::ExecutionCluster;
|
||||
/// Exposes cluster restrictions.
|
||||
pub use crate::execution::ExecutionClusterPolicy;
|
||||
/// Exposes the result of waiting for transaction confirmation.
|
||||
pub use crate::execution::ExecutionConfirmationResult;
|
||||
/// Exposes transaction confirmation states.
|
||||
pub use crate::execution::ExecutionConfirmationStatus;
|
||||
/// Exposes explicit execution cost ceilings.
|
||||
pub use crate::execution::ExecutionCostLimit;
|
||||
/// Exposes the complete execution policy.
|
||||
pub use crate::execution::ExecutionPolicy;
|
||||
/// Exposes the result of a transaction send adapter.
|
||||
pub use crate::execution::ExecutionSendResult;
|
||||
/// Exposes the simulation policy.
|
||||
pub use crate::execution::ExecutionSimulationPolicy;
|
||||
/// Exposes the simulation result contract.
|
||||
pub use crate::execution::ExecutionSimulationResult;
|
||||
/// Exposes one planned instruction account.
|
||||
pub use crate::execution::PlannedAccount;
|
||||
/// Exposes one encoded planned instruction.
|
||||
pub use crate::execution::PlannedInstruction;
|
||||
/// Exposes post-execution replay diagnostics.
|
||||
pub use crate::execution::PostExecutionDiagnostic;
|
||||
/// Exposes post-execution validation requirements.
|
||||
pub use crate::execution::PostExecutionValidationPolicy;
|
||||
/// Exposes a typed execution plan.
|
||||
pub use crate::execution::PreparedExecutionPlan;
|
||||
/// Exposes one required signer.
|
||||
pub use crate::execution::RequiredSigner;
|
||||
/// Exposes the typed executor contract.
|
||||
pub use crate::execution::TypedInstructionExecutor;
|
||||
/// Exposes the legacy common execution plan type.
|
||||
pub use crate::executor::ExecutionPlan;
|
||||
/// Exposes the legacy common execution request type.
|
||||
pub use crate::executor::ExecutionRequest;
|
||||
/// Exposes the legacy common execution support enum.
|
||||
pub use crate::executor::ExecutionSupport;
|
||||
/// Exposes the legacy common instruction executor trait.
|
||||
pub use crate::executor::InstructionExecutor;
|
||||
/// Exposes the compact JSON payload serializer.
|
||||
pub use crate::executor::serialize_payload_json;
|
||||
/// Exposes the pretty JSON payload serializer.
|
||||
pub use crate::executor::serialize_payload_json_pretty;
|
||||
Reference in New Issue
Block a user