Skip to content

Commit 96fbd9a

Browse files
committed
improve & automate slash handling (#250)
* improve & automate slash handling
1 parent ff9f810 commit 96fbd9a

File tree

17 files changed

+214
-105
lines changed

17 files changed

+214
-105
lines changed

Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ setup:
4747
make start-compute-pool
4848

4949
setup-dev-env:
50-
make set-min-stake-amount
5150
make create-training-domain
5251
make create-synth-data-domain
5352
make mint-ai-tokens-to-federator

discovery/src/chainsync/sync.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ impl ChainSync {
2929
contracts,
3030
}
3131
}
32+
3233
async fn sync_single_node(
3334
node_store: Arc<NodeStore>,
3435
contracts: Arc<Contracts>,
@@ -47,16 +48,6 @@ impl ChainSync {
4748
anyhow::anyhow!("Invalid node address")
4849
})?;
4950

50-
// Handle potential errors from async calls
51-
let is_blacklisted = contracts
52-
.compute_pool
53-
.is_node_blacklisted(node.node.compute_pool_id, node_address)
54-
.await
55-
.map_err(|e| {
56-
eprintln!("Error checking if node is blacklisted: {}", e);
57-
anyhow::anyhow!("Failed to check blacklist status")
58-
})?;
59-
6051
let node_info = contracts
6152
.compute_registry
6253
.get_node(provider_address, node_address)
@@ -79,6 +70,16 @@ impl ChainSync {
7970
n.is_active = is_active;
8071
n.is_validated = is_validated;
8172
n.is_provider_whitelisted = provider_info.is_whitelisted;
73+
74+
// Handle potential errors from async calls
75+
let is_blacklisted = contracts
76+
.compute_pool
77+
.is_node_blacklisted(node.node.compute_pool_id, node_address)
78+
.await
79+
.map_err(|e| {
80+
eprintln!("Error checking if node is blacklisted: {}", e);
81+
anyhow::anyhow!("Failed to check blacklist status")
82+
})?;
8283
n.is_blacklisted = is_blacklisted;
8384
match node_store.update_node(n) {
8485
Ok(_) => (),

discovery/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ async fn main() -> Result<()> {
5858
.with_ai_token()
5959
.with_prime_network()
6060
.with_compute_pool()
61+
.with_stake_manager()
6162
.build()
6263
.unwrap(),
6364
);

shared/src/web3/contracts/implementations/compute_registry_contract.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::web3::contracts::helpers::utils::get_selector;
66
use crate::web3::wallet::Wallet;
77
use alloy::dyn_abi::DynSolValue;
88
use alloy::primitives::{Address, U256};
9+
use anyhow::Result;
910

1011
#[derive(Clone)]
1112
pub struct ComputeRegistryContract {
@@ -57,12 +58,11 @@ impl ComputeRegistryContract {
5758
provider_response.first().unwrap().as_uint().unwrap().0,
5859
))
5960
}
60-
6161
pub async fn get_node(
6262
&self,
6363
provider_address: Address,
6464
node_address: Address,
65-
) -> Result<(bool, bool), Box<dyn std::error::Error>> {
65+
) -> anyhow::Result<(bool, bool)> {
6666
let get_node_selector = get_selector("getNode(address,address)");
6767

6868
let node_response = self
@@ -83,14 +83,14 @@ impl ComputeRegistryContract {
8383
let node_subkey = node_tuple[1].as_address().unwrap();
8484

8585
if node_provider != provider_address || node_subkey != node_address {
86-
return Err("Node does not match provider or subkey".into());
86+
return Err(anyhow::anyhow!("Node does not match provider or subkey"));
8787
}
8888

8989
let active = node_tuple[5].as_bool().unwrap();
9090
let validated = node_tuple[6].as_bool().unwrap();
9191
Ok((active, validated))
9292
} else {
93-
Err("Node is not registered".into())
93+
Err(anyhow::anyhow!("Node is not registered"))
9494
}
9595
}
9696
}

shared/src/web3/contracts/implementations/prime_network_contract.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ impl PrimeNetworkContract {
197197

198198
Ok(invalidate_work_tx)
199199
}
200+
200201
pub async fn get_validator_role(&self) -> Result<Vec<Address>, Error> {
201202
let hash = keccak256(b"VALIDATOR_ROLE");
202203
let value = DynSolValue::FixedBytes(hash, 32);

shared/src/web3/contracts/implementations/stake_manager.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ impl StakeManagerContract {
3030
.0;
3131
Ok(minimum)
3232
}
33+
3334
pub async fn get_stake(&self, staker: Address) -> Result<U256, Box<dyn std::error::Error>> {
3435
let result = self
3536
.instance

validator/src/main.rs

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pub mod store;
22
pub mod validators;
33
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
44
use alloy::primitives::utils::Unit;
5-
use alloy::primitives::U256;
5+
use alloy::primitives::{Address, U256};
66
use anyhow::{Context, Result};
77
use clap::Parser;
88
use log::{debug, LevelFilter};
@@ -245,8 +245,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
245245
};
246246
info!(
247247
"Synthetic validator has penalty: {} ({})",
248-
penalty,
249-
Unit::ETHER.wei()
248+
penalty, args.validator_penalty
250249
);
251250

252251
Some(SyntheticDataValidator::new(
@@ -358,7 +357,70 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
358357
}
359358
};
360359

361-
if let Err(e) = hardware_validator.validate_nodes(nodes).await {
360+
// Ensure nodes have enough stake
361+
let mut nodes_with_enough_stake = Vec::new();
362+
let stake_manager = match contracts.stake_manager.as_ref() {
363+
Some(manager) => manager,
364+
None => {
365+
error!("Stake manager contract not initialized");
366+
continue;
367+
}
368+
};
369+
370+
let mut provider_stake_cache: std::collections::HashMap<String, (U256, U256)> =
371+
std::collections::HashMap::new();
372+
for node in nodes {
373+
let provider_address_str = &node.node.provider_address;
374+
let provider_address = match Address::from_str(provider_address_str) {
375+
Ok(address) => address,
376+
Err(e) => {
377+
error!(
378+
"Failed to parse provider address {}: {}",
379+
provider_address_str, e
380+
);
381+
continue;
382+
}
383+
};
384+
385+
let (stake, required_stake) =
386+
if let Some(&cached_info) = provider_stake_cache.get(provider_address_str) {
387+
cached_info
388+
} else {
389+
let stake = stake_manager
390+
.get_stake(provider_address)
391+
.await
392+
.unwrap_or_default();
393+
let total_compute = contracts
394+
.compute_registry
395+
.get_provider_total_compute(provider_address)
396+
.await
397+
.unwrap_or_default();
398+
let required_stake = stake_manager
399+
.calculate_stake(U256::from(0), total_compute)
400+
.await
401+
.unwrap_or_default();
402+
403+
provider_stake_cache
404+
.insert(provider_address_str.clone(), (stake, required_stake));
405+
(stake, required_stake)
406+
};
407+
408+
if stake >= required_stake {
409+
nodes_with_enough_stake.push(node);
410+
} else {
411+
info!(
412+
"Node {} has insufficient stake: {} (required: {})",
413+
node.node.id,
414+
stake / Unit::ETHER.wei(),
415+
required_stake / Unit::ETHER.wei()
416+
);
417+
}
418+
}
419+
420+
if let Err(e) = hardware_validator
421+
.validate_nodes(nodes_with_enough_stake)
422+
.await
423+
{
362424
error!("Error validating nodes: {:#}", e);
363425
}
364426
}

validator/src/validators/synthetic_data.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ impl SyntheticDataValidator {
157157
let data = hex::decode(work_key)
158158
.map_err(|e| Error::msg(format!("Failed to decode hex work key: {}", e)))?;
159159
info!("Invalidating work: {}", work_key);
160+
160161
match self
161162
.prime_network
162163
.invalidate_work(self.pool_id, self.penalty, data)

worker/src/api/routes/invite.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ pub async fn invite_node(
4141
{
4242
Ok(result) => {
4343
Console::success(&format!("Successfully joined compute pool: {:?}", result));
44-
Console::info("Starting to send heartbeats now.", "");
4544
}
4645
Err(err) => {
4746
Console::error(&format!("Error joining compute pool: {:?}", err));
@@ -61,7 +60,6 @@ pub async fn invite_node(
6160
)
6261
};
6362

64-
println!("Starting heartbeat service with endpoint: {}", endpoint);
6563
let _ = app_state.heartbeat_service.start(endpoint).await;
6664

6765
HttpResponse::Accepted().json(json!({

0 commit comments

Comments
 (0)