mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-06-28 11:10:08 +00:00
fix(idl-gen): sort types array for deterministic output
The IDL `types` array was emitted in HashMap iteration order by spel-framework-core, which is non-deterministic across processes. Two independent regenerations of the same source could therefore disagree on type ordering, producing different bytes. This is what makes the check-idl CI job flaky: a PR's committed IDL is generated locally with one ordering, but CI regenerates with a different ordering and the diff fails — including PRs that were green when posted then breaking main after merge. Sort the top-level `types` array by name before serializing so output is byte-stable regardless of where idl-gen runs. Enable serde_json's `preserve_order` feature so the Value round-trip preserves struct-field key order (otherwise all keys would alphabetize and churn every artifact). Only top-level `types` was unstable; variants and fields already follow source order. Committed artifacts are unchanged — they happened to already be in sorted order.
This commit is contained in:
parent
7461c9552b
commit
b0ac30039b
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2850,6 +2850,7 @@ version = "1.0.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
dependencies = [
|
||||
"indexmap 2.14.0",
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
|
||||
@ -326,6 +326,18 @@
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"name": "MetadataStandard",
|
||||
"kind": "enum",
|
||||
"variants": [
|
||||
{
|
||||
"name": "Simple"
|
||||
},
|
||||
{
|
||||
"name": "Expanded"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ObservationEntry",
|
||||
"kind": "struct",
|
||||
@ -339,18 +351,6 @@
|
||||
"type": "i64"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "MetadataStandard",
|
||||
"kind": "enum",
|
||||
"variants": [
|
||||
{
|
||||
"name": "Simple"
|
||||
},
|
||||
{
|
||||
"name": "Expanded"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"instruction_type": "stablecoin_core::Instruction"
|
||||
|
||||
@ -14,5 +14,8 @@ path = "src/main.rs"
|
||||
spel-framework-core = { git = "https://github.com/logos-co/spel.git", tag = "v0.3.0", features = [
|
||||
"idl-gen",
|
||||
] }
|
||||
serde_json = "1.0"
|
||||
# `preserve_order` keeps object keys in struct-declaration order when
|
||||
# round-tripping through serde_json::Value (see main.rs), so the only
|
||||
# reordering we apply is sorting the `types` array.
|
||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||
toml = "0.8"
|
||||
|
||||
@ -16,13 +16,37 @@ fn main() {
|
||||
let dep_dirs = find_path_dep_dirs(&path);
|
||||
|
||||
match spel_framework_core::idl_gen::generate_idl_from_file_with_deps(&path, &dep_dirs) {
|
||||
Ok(idl) => match serde_json::to_string_pretty(&idl) {
|
||||
Ok(json) => println!("{json}"),
|
||||
Err(e) => {
|
||||
eprintln!("Error serializing IDL to JSON: {e}");
|
||||
process::exit(1);
|
||||
Ok(idl) => {
|
||||
// spel-framework emits the top-level `types` array in HashMap
|
||||
// iteration order, which is non-deterministic across processes.
|
||||
// Sort it by name so regenerated IDL is byte-stable regardless of
|
||||
// where it runs (local `make idl` vs CI vs another contributor).
|
||||
let mut value = match serde_json::to_value(&idl) {
|
||||
Ok(value) => value,
|
||||
Err(e) => {
|
||||
eprintln!("Error converting IDL to JSON value: {e}");
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
if let Some(types) = value.get_mut("types").and_then(|t| t.as_array_mut()) {
|
||||
types.sort_by(|a, b| {
|
||||
let name = |v: &serde_json::Value| {
|
||||
v.get("name")
|
||||
.and_then(|n| n.as_str())
|
||||
.unwrap_or("")
|
||||
.to_owned()
|
||||
};
|
||||
name(a).cmp(&name(b))
|
||||
});
|
||||
}
|
||||
},
|
||||
match serde_json::to_string_pretty(&value) {
|
||||
Ok(json) => println!("{json}"),
|
||||
Err(e) => {
|
||||
eprintln!("Error serializing IDL to JSON: {e}");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error: {e}");
|
||||
process::exit(1);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user