0.3.15-pre.014
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-store-postgres-lib/src/raw_transaction.rs
|
||||
// version: 8
|
||||
// version: 9
|
||||
|
||||
pub(crate) mod cursor;
|
||||
|
||||
@@ -48,8 +48,26 @@ const UPDATE_ARCHIVED_TRANSACTION_SQL: &str =
|
||||
"UPDATE ksp_raw_transactions SET payload = NULL, retention_state = 'archived' WHERE signature = $1 AND retention_state = 'full'";
|
||||
const UPDATE_PURGED_TRANSACTION_SQL: &str = "UPDATE ksp_raw_transactions SET block_time_unix_millis = NULL, payload = NULL, retention_state = 'purged' WHERE signature = $1 AND retention_state = 'archived'";
|
||||
|
||||
struct RawLogMessagesContentConflictDiagnostic {
|
||||
available: bool,
|
||||
first_mismatch_index: std::string::String,
|
||||
incoming_count: usize,
|
||||
incoming_first_kind: &'static str,
|
||||
incoming_first_length: usize,
|
||||
incoming_has_truncation_marker: bool,
|
||||
incoming_prefix_of_stored: bool,
|
||||
incoming_state: &'static str,
|
||||
stored_count: usize,
|
||||
stored_first_kind: &'static str,
|
||||
stored_first_length: usize,
|
||||
stored_has_truncation_marker: bool,
|
||||
stored_prefix_of_incoming: bool,
|
||||
stored_state: &'static str,
|
||||
}
|
||||
|
||||
struct RawPayloadContentConflictDiagnostic {
|
||||
available: bool,
|
||||
log_messages: RawLogMessagesContentConflictDiagnostic,
|
||||
meta_mismatch: bool,
|
||||
meta_mismatch_fields: std::string::String,
|
||||
other_mismatch: bool,
|
||||
@@ -63,6 +81,7 @@ struct RawTransactionContentConflictDiagnostic {
|
||||
content_hash_mismatch: bool,
|
||||
format_id_mismatch: bool,
|
||||
format_version_mismatch: bool,
|
||||
log_messages: RawLogMessagesContentConflictDiagnostic,
|
||||
meta_mismatch_fields: std::string::String,
|
||||
payload_bytes_mismatch: bool,
|
||||
payload_diagnostic_available: bool,
|
||||
@@ -1138,6 +1157,7 @@ fn raw_transaction_content_conflict_diagnostic(
|
||||
content_hash_mismatch: stored.payload().content_hash() != incoming.payload().content_hash(),
|
||||
format_id_mismatch: stored.payload().format_id() != incoming.payload().format_id(),
|
||||
format_version_mismatch: stored.payload().format_version() != incoming.payload().format_version(),
|
||||
log_messages: payload.log_messages,
|
||||
meta_mismatch_fields: payload.meta_mismatch_fields,
|
||||
payload_bytes_mismatch: stored.payload().bytes() != incoming.payload().bytes(),
|
||||
payload_diagnostic_available: payload.available,
|
||||
@@ -1158,6 +1178,7 @@ fn raw_payload_content_conflict_diagnostic(stored: &[u8], incoming: &[u8]) -> Ra
|
||||
_ => {
|
||||
return RawPayloadContentConflictDiagnostic {
|
||||
available: false,
|
||||
log_messages: raw_log_messages_content_conflict_diagnostic(std::option::Option::None, std::option::Option::None),
|
||||
meta_mismatch: false,
|
||||
meta_mismatch_fields: "unavailable".to_owned(),
|
||||
other_mismatch: false,
|
||||
@@ -1173,8 +1194,10 @@ fn raw_payload_content_conflict_diagnostic(stored: &[u8], incoming: &[u8]) -> Ra
|
||||
let transaction_index_mismatch = stored.get("transactionIndex") != incoming.get("transactionIndex");
|
||||
let other_mismatch = json_object_other_fields_mismatch(&stored, &incoming, RAW_TRANSACTION_CONTENT_CONFLICT_PAYLOAD_FIELDS.as_slice());
|
||||
let meta_mismatch_fields = raw_meta_content_conflict_fields(stored.get("meta"), incoming.get("meta"));
|
||||
let log_messages = raw_log_messages_content_conflict_diagnostic(stored.get("meta"), incoming.get("meta"));
|
||||
return RawPayloadContentConflictDiagnostic {
|
||||
available: true,
|
||||
log_messages,
|
||||
meta_mismatch,
|
||||
meta_mismatch_fields,
|
||||
other_mismatch,
|
||||
@@ -1184,6 +1207,140 @@ fn raw_payload_content_conflict_diagnostic(stored: &[u8], incoming: &[u8]) -> Ra
|
||||
};
|
||||
}
|
||||
|
||||
fn raw_log_messages_content_conflict_diagnostic(
|
||||
stored_meta: std::option::Option<&serde_json::Value>,
|
||||
incoming_meta: std::option::Option<&serde_json::Value>,
|
||||
) -> RawLogMessagesContentConflictDiagnostic {
|
||||
let stored = raw_log_messages_value(stored_meta);
|
||||
let incoming = raw_log_messages_value(incoming_meta);
|
||||
let stored_state = raw_log_messages_state(stored);
|
||||
let incoming_state = raw_log_messages_state(incoming);
|
||||
let (stored_values, incoming_values) = match (stored, incoming) {
|
||||
(std::option::Option::Some(serde_json::Value::Array(stored)), std::option::Option::Some(serde_json::Value::Array(incoming))) => {
|
||||
(stored.as_slice(), incoming.as_slice())
|
||||
},
|
||||
_ => {
|
||||
return RawLogMessagesContentConflictDiagnostic {
|
||||
available: false,
|
||||
first_mismatch_index: "unavailable".to_owned(),
|
||||
incoming_count: raw_log_messages_count(incoming),
|
||||
incoming_first_kind: "unavailable",
|
||||
incoming_first_length: 0,
|
||||
incoming_has_truncation_marker: raw_log_messages_has_truncation_marker(incoming),
|
||||
incoming_prefix_of_stored: false,
|
||||
incoming_state,
|
||||
stored_count: raw_log_messages_count(stored),
|
||||
stored_first_kind: "unavailable",
|
||||
stored_first_length: 0,
|
||||
stored_has_truncation_marker: raw_log_messages_has_truncation_marker(stored),
|
||||
stored_prefix_of_incoming: false,
|
||||
stored_state,
|
||||
};
|
||||
},
|
||||
};
|
||||
let shared_len = stored_values.len().min(incoming_values.len());
|
||||
let first_mismatch = stored_values.iter().zip(incoming_values.iter()).position(|(stored, incoming)| return stored != incoming).or_else(|| {
|
||||
if stored_values.len() == incoming_values.len() {
|
||||
return std::option::Option::None;
|
||||
}
|
||||
return std::option::Option::Some(shared_len);
|
||||
});
|
||||
let (stored_first_kind, stored_first_length) = raw_log_message_kind_and_length(first_mismatch.and_then(|index| return stored_values.get(index)));
|
||||
let (incoming_first_kind, incoming_first_length) = raw_log_message_kind_and_length(first_mismatch.and_then(|index| return incoming_values.get(index)));
|
||||
let first_mismatch_index = match first_mismatch {
|
||||
std::option::Option::Some(value) => value.to_string(),
|
||||
std::option::Option::None => "none".to_owned(),
|
||||
};
|
||||
return RawLogMessagesContentConflictDiagnostic {
|
||||
available: true,
|
||||
first_mismatch_index,
|
||||
incoming_count: incoming_values.len(),
|
||||
incoming_first_kind,
|
||||
incoming_first_length,
|
||||
incoming_has_truncation_marker: raw_log_message_array_has_truncation_marker(incoming_values),
|
||||
incoming_prefix_of_stored: raw_json_array_is_prefix(incoming_values, stored_values),
|
||||
incoming_state,
|
||||
stored_count: stored_values.len(),
|
||||
stored_first_kind,
|
||||
stored_first_length,
|
||||
stored_has_truncation_marker: raw_log_message_array_has_truncation_marker(stored_values),
|
||||
stored_prefix_of_incoming: raw_json_array_is_prefix(stored_values, incoming_values),
|
||||
stored_state,
|
||||
};
|
||||
}
|
||||
|
||||
fn raw_log_messages_value(meta: std::option::Option<&serde_json::Value>) -> std::option::Option<&serde_json::Value> {
|
||||
return match meta {
|
||||
std::option::Option::Some(serde_json::Value::Object(meta)) => meta.get("logMessages"),
|
||||
_ => std::option::Option::None,
|
||||
};
|
||||
}
|
||||
|
||||
fn raw_log_messages_state(value: std::option::Option<&serde_json::Value>) -> &'static str {
|
||||
return match value {
|
||||
std::option::Option::None => "missing",
|
||||
std::option::Option::Some(serde_json::Value::Null) => "null",
|
||||
std::option::Option::Some(serde_json::Value::Array(_)) => "array",
|
||||
std::option::Option::Some(_) => "other",
|
||||
};
|
||||
}
|
||||
|
||||
fn raw_log_messages_count(value: std::option::Option<&serde_json::Value>) -> usize {
|
||||
return match value {
|
||||
std::option::Option::Some(serde_json::Value::Array(values)) => values.len(),
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
||||
fn raw_json_array_is_prefix(prefix: &[serde_json::Value], values: &[serde_json::Value]) -> bool {
|
||||
if prefix.len() > values.len() {
|
||||
return false;
|
||||
}
|
||||
return prefix.iter().zip(values.iter()).all(|(left, right)| return left == right);
|
||||
}
|
||||
|
||||
fn raw_log_message_kind_and_length(value: std::option::Option<&serde_json::Value>) -> (&'static str, usize) {
|
||||
let line = match value {
|
||||
std::option::Option::Some(serde_json::Value::String(value)) => value.as_str(),
|
||||
std::option::Option::Some(_) => return ("non_string", 0),
|
||||
std::option::Option::None => return ("missing", 0),
|
||||
};
|
||||
let kind = if line.starts_with("Log truncated") || line.starts_with("log truncated") {
|
||||
"log_truncated"
|
||||
} else if line.starts_with("Program log:") {
|
||||
"program_log"
|
||||
} else if line.starts_with("Program data:") {
|
||||
"program_data"
|
||||
} else if line.starts_with("Program ") && line.contains(" invoke [") {
|
||||
"program_invoke"
|
||||
} else if line.starts_with("Program ") && line.ends_with(" success") {
|
||||
"program_success"
|
||||
} else if line.starts_with("Program ") && line.contains(" failed:") {
|
||||
"program_failed"
|
||||
} else if line.starts_with("Program ") && line.contains(" consumed ") && line.contains(" compute units") {
|
||||
"compute_units"
|
||||
} else {
|
||||
"other"
|
||||
};
|
||||
return (kind, line.len());
|
||||
}
|
||||
|
||||
fn raw_log_messages_has_truncation_marker(value: std::option::Option<&serde_json::Value>) -> bool {
|
||||
return match value {
|
||||
std::option::Option::Some(serde_json::Value::Array(values)) => raw_log_message_array_has_truncation_marker(values.as_slice()),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
fn raw_log_message_array_has_truncation_marker(values: &[serde_json::Value]) -> bool {
|
||||
return values.iter().any(|value| {
|
||||
return match value {
|
||||
serde_json::Value::String(line) => line.starts_with("Log truncated") || line.starts_with("log truncated"),
|
||||
_ => false,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
fn raw_meta_content_conflict_fields(stored: std::option::Option<&serde_json::Value>, incoming: std::option::Option<&serde_json::Value>) -> std::string::String {
|
||||
if stored == incoming {
|
||||
return "none".to_owned();
|
||||
@@ -1227,6 +1384,8 @@ fn log_raw_transaction_content_conflict(
|
||||
target: crate::TRACING_TARGET,
|
||||
domain = "store.raw_transaction.content_conflict",
|
||||
network = network.as_str(),
|
||||
stored_slot = stored.slot(),
|
||||
incoming_slot = incoming.slot(),
|
||||
slot_mismatch = diagnostic.slot_mismatch,
|
||||
block_time_mismatch = diagnostic.block_time_mismatch,
|
||||
format_id_mismatch = diagnostic.format_id_mismatch,
|
||||
@@ -1240,6 +1399,20 @@ fn log_raw_transaction_content_conflict(
|
||||
transaction_index_mismatch = diagnostic.payload_transaction_index_mismatch,
|
||||
payload_other_mismatch = diagnostic.payload_other_mismatch,
|
||||
meta_mismatch_fields = diagnostic.meta_mismatch_fields.as_str(),
|
||||
log_messages_diagnostic_available = diagnostic.log_messages.available,
|
||||
stored_log_messages_state = diagnostic.log_messages.stored_state,
|
||||
incoming_log_messages_state = diagnostic.log_messages.incoming_state,
|
||||
stored_log_messages_count = diagnostic.log_messages.stored_count,
|
||||
incoming_log_messages_count = diagnostic.log_messages.incoming_count,
|
||||
log_messages_first_mismatch_index = diagnostic.log_messages.first_mismatch_index.as_str(),
|
||||
stored_log_messages_first_kind = diagnostic.log_messages.stored_first_kind,
|
||||
incoming_log_messages_first_kind = diagnostic.log_messages.incoming_first_kind,
|
||||
stored_log_messages_first_length = diagnostic.log_messages.stored_first_length,
|
||||
incoming_log_messages_first_length = diagnostic.log_messages.incoming_first_length,
|
||||
stored_log_messages_prefix_of_incoming = diagnostic.log_messages.stored_prefix_of_incoming,
|
||||
incoming_log_messages_prefix_of_stored = diagnostic.log_messages.incoming_prefix_of_stored,
|
||||
stored_log_messages_has_truncation_marker = diagnostic.log_messages.stored_has_truncation_marker,
|
||||
incoming_log_messages_has_truncation_marker = diagnostic.log_messages.incoming_has_truncation_marker,
|
||||
"PostgreSQL Store rejected divergent canonical RAW transaction"
|
||||
);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user