diff --git a/src/blockchain/mod.rs b/src/blockchain/mod.rs index 7a3fe7c0..34552cfd 100644 --- a/src/blockchain/mod.rs +++ b/src/blockchain/mod.rs @@ -560,7 +560,13 @@ impl Blockchain for KvStoreChain { if let Some(chance) = stakers.get(&addr) { if let Some(staker_info) = self.get_staker(addr.clone())? { if Into::::into(proof.vrf_output.clone()) <= *chance { - let preimage = format!("{}-{}-{}", hex::encode(randomness), epoch, slot); + let preimage = format!( + "{}-{}-{}-{}", + hex::encode(randomness), + epoch, + slot, + proof.attempt + ); return Ok(Vrf::verify( &staker_info.vrf_pub_key, @@ -578,6 +584,7 @@ impl Blockchain for KvStoreChain { timestamp: u32, wallet: &TxBuilder, ) -> Result, BlockchainError> { + const MAX_ATTEMPTS: u32 = 3; let (epoch, slot) = self.epoch_slot(timestamp); let randomness = self.epoch_randomness()?; let stakers = self.get_stakers()?; @@ -586,13 +593,17 @@ impl Blockchain for KvStoreChain { .into_iter() .map(|(k, v)| (k, (u64::from(v) as f64 / sum_stakes as f64) as f32)) .collect(); - if let Some(chance) = stakers.get(&wallet.get_address()) { - let (vrf_output, vrf_proof) = wallet.generate_random(randomness, epoch, slot); - if Into::::into(vrf_output.clone()) <= *chance { - return Ok(Some(ValidatorProof { - vrf_output, - vrf_proof, - })); + for attempt in 0..MAX_ATTEMPTS { + if let Some(chance) = stakers.get(&wallet.get_address()) { + let (vrf_output, vrf_proof) = + wallet.generate_random(randomness, epoch, slot, attempt); + if Into::::into(vrf_output.clone()) <= *chance { + return Ok(Some(ValidatorProof { + attempt, + vrf_output, + vrf_proof, + })); + } } } Ok(None) diff --git a/src/client/messages.rs b/src/client/messages.rs index acee1be0..5e25abf5 100644 --- a/src/client/messages.rs +++ b/src/client/messages.rs @@ -36,7 +36,6 @@ pub struct GetStatsResponse { pub version: String, pub network: String, pub validator_claim: Option, - pub random_number: f32, } #[derive(Deserialize, Serialize, Debug, Clone)] diff --git a/src/core/header.rs b/src/core/header.rs index 5389a35e..14a06e27 100644 --- a/src/core/header.rs +++ b/src/core/header.rs @@ -4,6 +4,7 @@ use crate::crypto::{SignatureScheme, VerifiableRandomFunction}; // A proof that you are the validator for this block #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash)] pub struct ValidatorProof { + pub attempt: u32, pub vrf_output: V::Out, pub vrf_proof: V::Proof, } diff --git a/src/node/api/get_stats.rs b/src/node/api/get_stats.rs index a248dc4d..cfd3c43d 100644 --- a/src/node/api/get_stats.rs +++ b/src/node/api/get_stats.rs @@ -12,12 +12,6 @@ pub async fn get_stats>( let context = context.read().await; let ts = context.network_timestamp(); let (epoch, slot) = context.blockchain.epoch_slot(ts); - let randomness = context.blockchain.epoch_randomness()?; - let random_number: f32 = context - .validator_wallet - .generate_random(randomness, epoch, slot) - .0 - .into(); Ok(GetStatsResponse { social_profiles: context.social_profiles.clone(), @@ -32,6 +26,5 @@ pub async fn get_stats>( version: env!("CARGO_PKG_VERSION").into(), network: context.network.clone(), validator_claim: context.validator_claim.clone(), - random_number, }) } diff --git a/src/node/context.rs b/src/node/context.rs index 288256af..3a20424e 100644 --- a/src/node/context.rs +++ b/src/node/context.rs @@ -103,7 +103,9 @@ impl> NodeContext { let (epoch_curr, slot_curr) = self.blockchain.epoch_slot(curr_claim.timestamp); let (epoch_req, slot_req) = self.blockchain.epoch_slot(claim.timestamp); if epoch_curr == epoch_req && slot_curr == slot_req { - return Ok(false); + if claim.proof.attempt >= curr_claim.proof.attempt { + return Ok(false); + } } } let ts = self.network_timestamp(); diff --git a/src/wallet/tx_builder.rs b/src/wallet/tx_builder.rs index d29e309f..3742e634 100644 --- a/src/wallet/tx_builder.rs +++ b/src/wallet/tx_builder.rs @@ -148,13 +148,14 @@ impl TxBuilder { randomness: ::Output, epoch: u32, slot: u32, + attempt: u32, ) -> ( ::Out, ::Proof, ) { Vrf::sign( &self.vrf_private_key, - format!("{}-{}-{}", hex::encode(randomness), epoch, slot).as_bytes(), + format!("{}-{}-{}-{}", hex::encode(randomness), epoch, slot, attempt).as_bytes(), ) } pub fn register_validator(