Skip to content

Commit c2ba34b

Browse files
author
EchoBT
committed
fix: correct netuid_index calculation and salt serialization
- Fix netuid_index formula: mecid*4096+netuid (was netuid*256+mecid) - Store salt as hex string to prevent JSON serialization corruption - Update bittensor-rs to 47a9370 with the same netuid_index fix - Update README with correct formula This fixes InvalidRevealCommitHashNotMatch errors during weight reveals.
1 parent 53dd4dd commit c2ba34b

4 files changed

Lines changed: 90 additions & 18 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ license = "MIT"
3030

3131
[workspace.dependencies]
3232
# Bittensor
33-
bittensor-rs = { git = "https://github.com/CortexLM/bittensor-rs", rev = "173979c" }
33+
bittensor-rs = { git = "https://github.com/CortexLM/bittensor-rs", rev = "47a9370" }
3434

3535
# Async runtime
3636
tokio = { version = "1.40", features = ["full", "sync", "macros", "rt-multi-thread"] }

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ H = Blake2b_256(SCALE(account, netuid_index, uids, weights, salt, version_key))
235235

236236
Where:
237237
```
238-
netuid_index = netuid × 256 + mechanism_id
238+
netuid_index = mechanism_id × 4096 + netuid
239239
```
240240

241241
3. Submit commit: `commit_mechanism_weights(netuid, mechanism_id, H)`

crates/bittensor-integration/src/weights.rs

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,22 +119,72 @@ pub struct PendingMechanismCommit {
119119
pub hash: String,
120120
pub uids: Vec<u16>,
121121
pub weights: Vec<u16>,
122-
pub salt: Vec<u16>,
122+
/// Salt stored as hex string to avoid JSON serialization issues with u16
123+
pub salt_hex: String,
123124
pub version_key: u64,
124125
pub epoch: u64,
125126
}
126127

128+
impl PendingMechanismCommit {
129+
/// Get salt as Vec<u16> from hex storage
130+
pub fn get_salt(&self) -> Vec<u16> {
131+
// Decode hex to bytes, then convert pairs of bytes to u16 (little-endian)
132+
let bytes = hex::decode(&self.salt_hex).unwrap_or_default();
133+
bytes
134+
.chunks(2)
135+
.map(|chunk| {
136+
if chunk.len() == 2 {
137+
u16::from_le_bytes([chunk[0], chunk[1]])
138+
} else {
139+
chunk[0] as u16
140+
}
141+
})
142+
.collect()
143+
}
144+
145+
/// Create salt_hex from Vec<u16>
146+
pub fn salt_to_hex(salt: &[u16]) -> String {
147+
// Convert each u16 to 2 bytes (little-endian) and hex encode
148+
let bytes: Vec<u8> = salt.iter().flat_map(|s| s.to_le_bytes()).collect();
149+
hex::encode(bytes)
150+
}
151+
}
152+
127153
/// Pending commit data using subtensor-compatible format (v2)
128154
#[derive(Clone, Debug, Serialize, Deserialize)]
129155
pub struct PendingCommitV2 {
130156
pub hash: String,
131157
pub uids: Vec<u16>,
132158
pub weights: Vec<u16>,
133-
pub salt: Vec<u16>,
159+
/// Salt stored as hex string to avoid JSON serialization issues
160+
pub salt_hex: String,
134161
pub version_key: u64,
135162
pub epoch: u64,
136163
}
137164

165+
impl PendingCommitV2 {
166+
/// Get salt as Vec<u16> from hex storage
167+
pub fn get_salt(&self) -> Vec<u16> {
168+
let bytes = hex::decode(&self.salt_hex).unwrap_or_default();
169+
bytes
170+
.chunks(2)
171+
.map(|chunk| {
172+
if chunk.len() == 2 {
173+
u16::from_le_bytes([chunk[0], chunk[1]])
174+
} else {
175+
chunk[0] as u16
176+
}
177+
})
178+
.collect()
179+
}
180+
181+
/// Create salt_hex from Vec<u16>
182+
pub fn salt_to_hex(salt: &[u16]) -> String {
183+
let bytes: Vec<u8> = salt.iter().flat_map(|s| s.to_le_bytes()).collect();
184+
hex::encode(bytes)
185+
}
186+
}
187+
138188
impl WeightSubmitter {
139189
/// Create a new weight submitter with persistence
140190
pub fn new(client: SubtensorClient, data_dir: Option<PathBuf>) -> Self {
@@ -279,12 +329,12 @@ impl WeightSubmitter {
279329
)
280330
.await?;
281331

282-
// Store pending commit for reveal
332+
// Store pending commit for reveal (salt as hex to avoid serialization issues)
283333
self.state.pending_commit = Some(PendingCommitV2 {
284334
hash: commit_data.commit_hash,
285335
uids: commit_data.uids,
286336
weights: commit_data.weights,
287-
salt: commit_data.salt,
337+
salt_hex: PendingCommitV2::salt_to_hex(&commit_data.salt),
288338
version_key: commit_data.version_key,
289339
epoch: self.current_epoch,
290340
});
@@ -300,15 +350,24 @@ impl WeightSubmitter {
300350

301351
// Convert uids to u64 for reveal_weights API
302352
let uids_u64: Vec<u64> = pending.uids.iter().map(|u| *u as u64).collect();
353+
let salt = pending.get_salt();
354+
355+
debug!(
356+
"Revealing: uids={:?}, weights={:?}, salt_hex={}, salt={:?}",
357+
pending.uids, pending.weights, pending.salt_hex, salt
358+
);
359+
360+
// Note: reveal_weights API expects &[u8] for salt, but we store as u16
361+
// The salt bytes are converted back from the hex storage
362+
let salt_bytes: Vec<u8> = hex::decode(&pending.salt_hex).unwrap_or_default();
303363

304364
let tx_hash = reveal_weights(
305365
self.client.client()?,
306366
self.client.signer()?,
307367
self.client.netuid(),
308368
&uids_u64,
309369
&pending.weights,
310-
// Convert salt u16 back to u8 for reveal_weights API (it converts internally)
311-
&pending.salt.iter().map(|s| *s as u8).collect::<Vec<u8>>(),
370+
&salt_bytes,
312371
pending.version_key,
313372
ExtrinsicWait::Finalized,
314373
)
@@ -434,8 +493,14 @@ impl WeightSubmitter {
434493
let mut pending_commits = Vec::new();
435494

436495
for (mechanism_id, uids, weights) in mechanism_weights {
437-
// Generate salt (8 bytes converted to u16)
496+
// Generate salt (8 u16 values)
438497
let salt = generate_salt(8);
498+
let salt_hex = PendingMechanismCommit::salt_to_hex(&salt);
499+
500+
debug!(
501+
"Commit mechanism {}: uids={:?}, weights={:?}, salt={:?}, salt_hex={}, version_key={}",
502+
mechanism_id, uids, weights, salt, salt_hex, version_key
503+
);
439504

440505
// Generate commit hash
441506
let commit_hash = generate_mechanism_commit_hash(
@@ -450,9 +515,10 @@ impl WeightSubmitter {
450515

451516
let commit_hash_hex = commit_hash_to_hex(&commit_hash);
452517
info!(
453-
"Generated commit for mechanism {}: {}",
518+
"Generated commit for mechanism {}: {} (salt_hex={})",
454519
mechanism_id,
455-
&commit_hash_hex[..16]
520+
&commit_hash_hex[..16],
521+
&salt_hex[..16]
456522
);
457523

458524
// Add to batch
@@ -462,13 +528,13 @@ impl WeightSubmitter {
462528
&commit_hash,
463529
));
464530

465-
// Store pending commit for later reveal
531+
// Store pending commit for later reveal (salt as hex to avoid serialization issues)
466532
pending_commits.push(PendingMechanismCommit {
467533
mechanism_id: *mechanism_id,
468534
hash: commit_hash_hex,
469535
uids: uids.clone(),
470536
weights: weights.clone(),
471-
salt: salt.iter().map(|b| *b as u16).collect(),
537+
salt_hex, // Already computed above
472538
version_key,
473539
epoch: self.current_epoch,
474540
});
@@ -525,6 +591,12 @@ impl WeightSubmitter {
525591
for (_, commit) in pending {
526592
let mechanism_id = commit.mechanism_id;
527593
let epoch = commit.epoch;
594+
let salt = commit.get_salt();
595+
596+
debug!(
597+
"Revealing mechanism {}: uids={:?}, weights={:?}, salt_hex={}, salt={:?}, version_key={}",
598+
mechanism_id, commit.uids, commit.weights, commit.salt_hex, salt, commit.version_key
599+
);
528600

529601
let tx_hash = reveal_mechanism_weights(
530602
self.client.client()?,
@@ -533,7 +605,7 @@ impl WeightSubmitter {
533605
mechanism_id,
534606
&commit.uids,
535607
&commit.weights,
536-
&commit.salt,
608+
&salt,
537609
commit.version_key,
538610
ExtrinsicWait::Finalized,
539611
)

crates/challenge-sdk/src/weights.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,10 @@ pub fn compute_subtensor_hash(
245245
) -> [u8; 32] {
246246
// Calculate netuid_index (NetUidStorageIndex)
247247
// In subtensor: netuid_index = get_mechanism_storage_index(netuid, mecid)
248-
// For main mechanism (id=0): netuid_index = netuid * 256
249-
// For other mechanisms: netuid_index = netuid * 256 + mecid
250-
let mecid = mechanism_id.unwrap_or(0);
251-
let netuid_index: u32 = (netuid as u32) * 256 + (mecid as u32);
248+
// GLOBAL_MAX_SUBNET_COUNT = 4096
249+
// Formula: mecid * 4096 + netuid
250+
let mecid = mechanism_id.unwrap_or(0) as u32;
251+
let netuid_index: u32 = mecid * 4096 + (netuid as u32);
252252

253253
// Create SCALE-encodable tuple matching subtensor's format
254254
let data = (

0 commit comments

Comments
 (0)