v0.5.3-pre.003
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
<!-- file: ks-lib/CHANGELOG.md -->
|
||||
<!-- version: 53 -->
|
||||
<!-- version: 54 -->
|
||||
|
||||
# CHANGELOG — ks-lib
|
||||
|
||||
## `0.5.3-pre.003`
|
||||
|
||||
- fait évoluer `MdCoreInstructionReplayInput` vers le contrat version 3 afin de transporter le contexte Core nécessaire aux futurs décodeurs : `block_time`, `stack_height`, parent CPI et `returnData` transactionnelle ;
|
||||
- renomme le contexte de transaction `outer_instructions_json` en `top_level_instructions_json` dans ce nouveau contrat store/replay, sans supprimer les usages historiques du terme `outer` lorsqu'ils décrivent encore explicitement une sémantique de décodeur existante ;
|
||||
- conserve le constructeur historique de replay pour les tests/sources synthétiques et ajoute l'enrichissement `with_core_context` utilisé par `ks-store`.
|
||||
|
||||
## `0.5.1-pre.008`
|
||||
|
||||
- retire la dépendance `ts-rs`, les dérivations/attributs TS-RS et les bindings TypeScript générés historiques de `ks-lib` ;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: ks-lib/src/decoder/api/contracts.rs
|
||||
// version: 9
|
||||
// version: 10
|
||||
|
||||
//! Backend-neutral contextual instruction decoder contracts.
|
||||
|
||||
@@ -511,7 +511,7 @@ mod tests {
|
||||
fn contextual_input_hash_changes_when_outer_context_changes() {
|
||||
let first = replay_input();
|
||||
let mut second = replay_input();
|
||||
second.outer_instructions_json = serde_json::json!([{
|
||||
second.top_level_instructions_json = serde_json::json!([{
|
||||
"instructionIndex": 0,
|
||||
"instructionPath": "0",
|
||||
"programId": "program",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: ks-lib/src/decoder/solana/core/compute_budget.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! Maximal current and historical Compute Budget instruction decoding.
|
||||
|
||||
@@ -341,7 +341,7 @@ fn compute_budget_outer_rows(
|
||||
input: &crate::MdCoreInstructionReplayInput,
|
||||
) -> std::vec::Vec<ComputeBudgetProfileRow> {
|
||||
let mut rows = std::vec::Vec::new();
|
||||
let outer_values = match input.outer_instructions_json.as_array() {
|
||||
let outer_values = match input.top_level_instructions_json.as_array() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return rows,
|
||||
};
|
||||
@@ -705,7 +705,7 @@ mod tests {
|
||||
fn replay_input_with_outer(
|
||||
bytes: &[u8],
|
||||
instruction_path: &str,
|
||||
outer_instructions_json: serde_json::Value,
|
||||
top_level_instructions_json: serde_json::Value,
|
||||
) -> crate::MdCoreInstructionReplayInput {
|
||||
let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
|
||||
let result = crate::MdCoreInstructionReplayInput::new(
|
||||
@@ -720,7 +720,7 @@ mod tests {
|
||||
serde_json::json!([]),
|
||||
std::option::Option::Some(serde_json::json!({"dataBase64": encoded})),
|
||||
std::option::Option::Some("payload-hash".to_string()),
|
||||
outer_instructions_json,
|
||||
top_level_instructions_json,
|
||||
serde_json::json!([]),
|
||||
serde_json::json!([]),
|
||||
serde_json::json!([]),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: ks-lib/src/decoder/solana/core/payload.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! Bounded native instruction payload helpers.
|
||||
|
||||
@@ -228,7 +228,7 @@ fn resolve_explicit_outer_instruction(
|
||||
input: &crate::MdCoreInstructionReplayInput,
|
||||
instruction_index: usize,
|
||||
) -> ks_core::Result<crate::DcSolanaCoreResolvedInstructionPayload> {
|
||||
let entries = match input.outer_instructions_json.as_array() {
|
||||
let entries = match input.top_level_instructions_json.as_array() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Err(ks_core::Error::invalid_state(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: ks-lib/src/decoder/solana/core/precompiles.rs
|
||||
// version: 6
|
||||
// version: 7
|
||||
|
||||
//! Bounded structural decoding for Solana signature verification precompiles.
|
||||
|
||||
@@ -1599,11 +1599,11 @@ mod tests {
|
||||
for (program_id, target, external) in cases {
|
||||
let mut missing =
|
||||
replay_input(program_id, target.clone(), vec![(0, external.clone())], false);
|
||||
missing.outer_instructions_json[0]["payloadJson"] = serde_json::Value::Null;
|
||||
missing.top_level_instructions_json[0]["payloadJson"] = serde_json::Value::Null;
|
||||
let missing_result = crate::decoder_solana_core_precompiles_decode(&missing);
|
||||
assert_eq!(missing_result.status, crate::DcApiDecoderOutcomeStatus::Failed);
|
||||
let mut invalid = replay_input(program_id, target, vec![(0, external)], false);
|
||||
invalid.outer_instructions_json[0]["payloadJson"] =
|
||||
invalid.top_level_instructions_json[0]["payloadJson"] =
|
||||
serde_json::json!({"dataBase64": "%%%"});
|
||||
let invalid_result = crate::decoder_solana_core_precompiles_decode(&invalid);
|
||||
assert_eq!(invalid_result.status, crate::DcApiDecoderOutcomeStatus::Failed);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: ks-lib/src/decoder/solana/core/slashing.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Exact structural decoding for the enshrined stateless Slashing Program.
|
||||
|
||||
@@ -413,7 +413,7 @@ fn preceding_ed25519_instruction(input: &crate::MdCoreInstructionReplayInput) ->
|
||||
});
|
||||
},
|
||||
};
|
||||
let previous = input.outer_instructions_json.as_array().and_then(|instructions| {
|
||||
let previous = input.top_level_instructions_json.as_array().and_then(|instructions| {
|
||||
return instructions.iter().find(|instruction| {
|
||||
return instruction
|
||||
.get("instructionIndex")
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// file: ks-lib/src/model/replay.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Source-neutral instruction replay input shared by decoders and stores.
|
||||
|
||||
/// Version of the normalized core replay contract.
|
||||
pub const MD_CORE_REPLAY_INPUT_CONTRACT_VERSION: u32 = 2;
|
||||
pub const MD_CORE_REPLAY_INPUT_CONTRACT_VERSION: u32 = 3;
|
||||
|
||||
/// Decoder replay input containing one instruction plus extracted transaction context.
|
||||
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
@@ -17,8 +17,14 @@ pub struct MdCoreInstructionReplayInput {
|
||||
pub signature: std::string::String,
|
||||
/// Transaction slot in Solana unsigned representation.
|
||||
pub slot: u64,
|
||||
/// Optional block timestamp as Unix seconds supplied by Solana.
|
||||
pub block_time: std::option::Option<i64>,
|
||||
/// Stable instruction path, for example `0` or `2/1`.
|
||||
pub instruction_path: std::string::String,
|
||||
/// Optional immediate or best-known parent instruction path for CPI inputs.
|
||||
pub parent_instruction_path: std::option::Option<std::string::String>,
|
||||
/// Optional runtime invocation stack height.
|
||||
pub stack_height: std::option::Option<u32>,
|
||||
/// Program id as non-empty base58 text.
|
||||
pub program_id: std::string::String,
|
||||
/// Optional surface hint supplied by an operator or upstream classifier.
|
||||
@@ -35,8 +41,10 @@ pub struct MdCoreInstructionReplayInput {
|
||||
pub instruction_payload_json: std::option::Option<serde_json::Value>,
|
||||
/// Optional deterministic hash of the retained instruction payload.
|
||||
pub instruction_payload_hash: std::option::Option<std::string::String>,
|
||||
/// Ordered outer instructions for the transaction.
|
||||
pub outer_instructions_json: serde_json::Value,
|
||||
/// Optional transaction return-data fact retained by Core.
|
||||
pub return_data: std::option::Option<crate::MdCanonicalReturnData>,
|
||||
/// Ordered top-level instructions for the transaction.
|
||||
pub top_level_instructions_json: serde_json::Value,
|
||||
/// Inner instruction tree or subtree relevant to the target instruction.
|
||||
pub inner_instructions_json: serde_json::Value,
|
||||
/// Ordered logs relevant to the transaction or target instruction.
|
||||
@@ -45,7 +53,7 @@ pub struct MdCoreInstructionReplayInput {
|
||||
pub balance_changes_json: serde_json::Value,
|
||||
}
|
||||
|
||||
impl MdCoreInstructionReplayInput {
|
||||
impl crate::MdCoreInstructionReplayInput {
|
||||
/// Builds a decoder replay input after validating its stable identity and array context.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
@@ -60,14 +68,14 @@ impl MdCoreInstructionReplayInput {
|
||||
instruction_accounts_json: serde_json::Value,
|
||||
instruction_payload_json: std::option::Option<serde_json::Value>,
|
||||
instruction_payload_hash: std::option::Option<std::string::String>,
|
||||
outer_instructions_json: serde_json::Value,
|
||||
top_level_instructions_json: serde_json::Value,
|
||||
inner_instructions_json: serde_json::Value,
|
||||
logs_json: serde_json::Value,
|
||||
balance_changes_json: serde_json::Value,
|
||||
) -> ks_core::Result<Self> {
|
||||
if !outer_instructions_json.is_array() {
|
||||
if !top_level_instructions_json.is_array() {
|
||||
return std::result::Result::Err(ks_core::Error::invalid_state(
|
||||
"core replay input outer instructions must be a JSON array",
|
||||
"core replay input top-level instructions must be a JSON array",
|
||||
));
|
||||
}
|
||||
let value = Self {
|
||||
@@ -75,7 +83,10 @@ impl MdCoreInstructionReplayInput {
|
||||
replay_input_key: replay_input_key.into(),
|
||||
signature: signature.into(),
|
||||
slot,
|
||||
block_time: std::option::Option::None,
|
||||
instruction_path: instruction_path.into(),
|
||||
parent_instruction_path: std::option::Option::None,
|
||||
stack_height: std::option::Option::None,
|
||||
program_id: program_id.into(),
|
||||
surface_code_hint: std::option::Option::None,
|
||||
transaction_failed,
|
||||
@@ -84,7 +95,8 @@ impl MdCoreInstructionReplayInput {
|
||||
instruction_accounts_json,
|
||||
instruction_payload_json,
|
||||
instruction_payload_hash,
|
||||
outer_instructions_json,
|
||||
return_data: std::option::Option::None,
|
||||
top_level_instructions_json,
|
||||
inner_instructions_json,
|
||||
logs_json,
|
||||
balance_changes_json,
|
||||
@@ -124,6 +136,47 @@ impl MdCoreInstructionReplayInput {
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
/// Adds transaction time, CPI ancestry and return-data context retained by Core.
|
||||
pub fn with_core_context(
|
||||
mut self,
|
||||
block_time: std::option::Option<i64>,
|
||||
parent_instruction_path: std::option::Option<std::string::String>,
|
||||
stack_height: std::option::Option<u32>,
|
||||
return_data: std::option::Option<crate::MdCanonicalReturnData>,
|
||||
) -> ks_core::Result<Self> {
|
||||
if parent_instruction_path
|
||||
.as_deref()
|
||||
.is_some_and(|value| return value.trim().is_empty())
|
||||
{
|
||||
return std::result::Result::Err(ks_core::Error::invalid_state(
|
||||
"core replay parent instruction path must not be empty when present",
|
||||
));
|
||||
}
|
||||
if stack_height.is_some_and(|value| return value == 0) {
|
||||
return std::result::Result::Err(ks_core::Error::invalid_state(
|
||||
"core replay stack height must be greater than zero when present",
|
||||
));
|
||||
}
|
||||
if parent_instruction_path.is_some() && stack_height.is_some_and(|value| return value <= 1)
|
||||
{
|
||||
return std::result::Result::Err(ks_core::Error::invalid_state(
|
||||
"core replay CPI stack height must be greater than one when present",
|
||||
));
|
||||
}
|
||||
if let std::option::Option::Some(value) = &return_data {
|
||||
if value.program_id.trim().is_empty() {
|
||||
return std::result::Result::Err(ks_core::Error::invalid_state(
|
||||
"core replay return-data program id must not be empty",
|
||||
));
|
||||
}
|
||||
}
|
||||
self.block_time = block_time;
|
||||
self.parent_instruction_path = parent_instruction_path;
|
||||
self.stack_height = stack_height;
|
||||
self.return_data = return_data;
|
||||
return std::result::Result::Ok(self);
|
||||
}
|
||||
|
||||
/// Adds an optional stable surface hint after validation.
|
||||
pub fn with_surface_code_hint(
|
||||
mut self,
|
||||
|
||||
Reference in New Issue
Block a user