Skip to content

Commit 5b6b57d

Browse files
committed
refactor: drop version field from v2 canonical JSON
The v2 canonical JSON previously included a "version":2 field to make the hashed content self-describing. Per review feedback, version is now carried out-of-band via RuntimeEvent.version (scale/serde) only, and the hashed content is a clean {event, event_type, payload} JSON. v2 canonical JSON is now: {"event":"<name>","event_type":134217729,"payload":"<hex>"} Updates: - canonical_event_json_v2: drop "version" key - doc comments in runtime_events.rs / tdx.rs / dstack-types/lib.rs updated to reflect the new v2 format - tests: expected canonical strings, the hash_input v2 assertion, and the key-order test no longer reference "version" Note: RuntimeEvent serde still emits "version":2 when writing events to /run/log/dstack/runtime_events.log (serde_roundtrip_preserves_version test covers that) — that is the on-disk format, not the hashed content.
1 parent de1d4a0 commit 5b6b57d

3 files changed

Lines changed: 11 additions & 13 deletions

File tree

cc-eventlog/src/runtime_events.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl RuntimeEvent {
113113
/// Compute the digest of the event.
114114
///
115115
/// - V1: `SHA(event_type_le || ":" || event_name || ":" || payload)`
116-
/// - V2: `SHA(canonical_json({"event":"...","event_type":134217729,"payload":"hex...","version":2}))`
116+
/// - V2: `SHA(canonical_json({"event":"...","event_type":134217729,"payload":"hex..."}))`
117117
pub fn digest<H: Hasher>(&self) -> H::Output {
118118
H::hash([self.hash_input().as_slice()])
119119
}
@@ -149,15 +149,14 @@ impl RuntimeEvent {
149149

150150
/// Construct the JCS (RFC 8785) canonical JSON used as the v2 digest input.
151151
///
152-
/// The JSON includes an explicit `version: 2` field so the content is
153-
/// self-describing for relying parties that don't know dstack's event schema.
154152
/// Keys and number/string formatting are handled by `serde_jcs` per RFC 8785.
153+
/// Version is carried out-of-band via `RuntimeEvent::version`, not in the
154+
/// hashed content.
155155
pub fn canonical_event_json_v2(event: &str, payload: &[u8]) -> String {
156156
let obj = serde_json::json!({
157157
"event": event,
158158
"event_type": DSTACK_RUNTIME_EVENT_TYPE,
159159
"payload": hex::encode(payload),
160-
"version": 2,
161160
});
162161
serde_jcs::to_string(&obj).or_panic("canonical JSON serialization failed")
163162
}
@@ -208,7 +207,7 @@ mod tests {
208207
let canonical = canonical_event_json_v2(&event.event, &event.payload);
209208
assert_eq!(
210209
canonical,
211-
r#"{"event":"compose-hash","event_type":134217729,"payload":"abcd","version":2}"#
210+
r#"{"event":"compose-hash","event_type":134217729,"payload":"abcd"}"#
212211
);
213212
let digest = event.digest::<Sha384>();
214213
let expected = Sha384::hash([canonical.as_bytes()]);
@@ -269,7 +268,7 @@ mod tests {
269268
// Exact bytewise output — JCS must be deterministic
270269
assert_eq!(
271270
canonical,
272-
r#"{"event":"event\"with\\special\nchars","event_type":134217729,"payload":"ff","version":2}"#
271+
r#"{"event":"event\"with\\special\nchars","event_type":134217729,"payload":"ff"}"#
273272
);
274273
}
275274

@@ -281,18 +280,16 @@ mod tests {
281280
let event_pos = canonical.find(r#""event":"#).unwrap();
282281
let event_type_pos = canonical.find(r#""event_type":"#).unwrap();
283282
let payload_pos = canonical.find(r#""payload":"#).unwrap();
284-
let version_pos = canonical.find(r#""version":"#).unwrap();
285283
assert!(event_pos < event_type_pos);
286284
assert!(event_type_pos < payload_pos);
287-
assert!(payload_pos < version_pos);
288285
}
289286

290287
#[test]
291288
fn canonical_json_empty_event_and_payload() {
292289
let canonical = canonical_event_json_v2("", &[]);
293290
assert_eq!(
294291
canonical,
295-
r#"{"event":"","event_type":134217729,"payload":"","version":2}"#
292+
r#"{"event":"","event_type":134217729,"payload":""}"#
296293
);
297294
}
298295

cc-eventlog/src/tdx.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
///
2020
/// For dstack runtime events (`event_type == DSTACK_RUNTIME_EVENT_TYPE`), the digest is:
2121
/// - V1: `sha384(event_type_le || ":" || event || ":" || payload)`
22-
/// - V2: `sha384(canonical_json({"event":"...","event_type":134217729,"payload":"hex...","version":2}))`
22+
/// - V2: `sha384(canonical_json({"event":"...","event_type":134217729,"payload":"hex..."}))`
2323
#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)]
2424
pub struct TdxEvent {
2525
/// IMR index, starts from 0
@@ -183,10 +183,11 @@ mod tests {
183183
let input_hex = tdx.hash_input.as_ref().expect("hash_input populated");
184184
let input = hex::decode(input_hex).unwrap();
185185
let input_str = std::str::from_utf8(&input).unwrap();
186-
// V2 hash_input is the canonical JSON
186+
// V2 hash_input is the canonical JSON (version is carried out-of-band)
187187
assert!(input_str.contains(r#""event":"compose-hash""#));
188-
assert!(input_str.contains(r#""version":2"#));
188+
assert!(input_str.contains(r#""event_type":134217729"#));
189189
assert!(input_str.contains(r#""payload":"abcd""#));
190+
assert!(!input_str.contains(r#""version""#));
190191
// And hashing it reproduces the digest
191192
let actual = Sha384::hash([input.as_slice()]);
192193
assert_eq!(actual.as_slice(), &tdx.digest);

dstack-types/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub enum EventLogVersion {
1919
#[default]
2020
V1,
2121
/// JSON canonical digest (JCS RFC 8785):
22-
/// `SHA({"event":"...","event_type":134217729,"payload":"hex...","version":2})`
22+
/// `SHA({"event":"...","event_type":134217729,"payload":"hex..."})`
2323
V2,
2424
}
2525

0 commit comments

Comments
 (0)