openmina_node_common/service/block_producer/
vrf_evaluator.rs1use mina_signer::Keypair;
2use node::{
3 block_producer::{
4 vrf_evaluator::{VrfEvaluationOutputWithHash, VrfEvaluatorInput},
5 BlockProducerEvent, BlockProducerVrfEvaluatorEvent,
6 },
7 core::channels::mpsc::{TrackedUnboundedReceiver, UnboundedSender},
8 event_source::Event,
9};
10use vrf::{VrfEvaluationInput, VrfEvaluationOutput};
11
12use crate::NodeService;
13
14pub fn vrf_evaluator(
15 event_sender: UnboundedSender<Event>,
16 mut vrf_evaluation_receiver: TrackedUnboundedReceiver<VrfEvaluatorInput>,
17 keypair: Keypair,
18) {
19 while let Some(vrf_evaluator_input) = vrf_evaluation_receiver.blocking_recv() {
20 let keypair = &keypair;
24 let VrfEvaluatorInput {
25 epoch_seed,
26 delegator_table,
27 global_slot,
28 total_currency,
29 staking_ledger_hash: _,
30 } = &*vrf_evaluator_input;
31
32 let vrf_result = delegator_table
33 .iter()
34 .find_map(|(index, (pub_key, stake))| {
35 let vrf_input = VrfEvaluationInput {
36 producer_key: keypair.clone(),
37 global_slot: *global_slot,
38 epoch_seed: epoch_seed.clone(),
39 account_pub_key: pub_key.clone(),
40 delegator_index: *index,
41 delegated_stake: (*stake).into(),
42 total_currency: (*total_currency).into(),
43 };
44
45 let vrf_result = vrf::evaluate_vrf(vrf_input).unwrap();
46
47 if let VrfEvaluationOutput::SlotWon(_) = vrf_result {
49 return Some(vrf_result);
50 }
51 None
52 })
53 .unwrap_or(VrfEvaluationOutput::SlotLost(*global_slot));
54
55 let vrf_result_with_hash = VrfEvaluationOutputWithHash::new(
56 vrf_result,
57 vrf_evaluator_input.staking_ledger_hash.clone(),
58 );
59
60 let _ = event_sender.send(
62 BlockProducerEvent::VrfEvaluator(BlockProducerVrfEvaluatorEvent::Evaluated(
63 vrf_result_with_hash,
64 ))
65 .into(),
66 );
67 }
68}
69
70impl node::block_producer_effectful::vrf_evaluator_effectful::BlockProducerVrfEvaluatorService
71 for NodeService
72{
73 fn evaluate(&mut self, data: VrfEvaluatorInput) {
74 if let Some(bp) = self.block_producer.as_mut() {
75 let _ = bp.vrf_evaluation_sender.tracked_send(data);
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use std::str::FromStr;
83
84 use node::account::AccountSecretKey;
86
87 use super::*;
88
89 #[test]
90 #[ignore]
91 fn test_vrf() {
92 let json = std::fs::read_to_string("/tmp/vrf.json").unwrap();
93 let vrf_evaluator_input: VrfEvaluatorInput = serde_json::from_str(&json).unwrap();
94
95 let private = "SOME_KEY";
96 let private = AccountSecretKey::from_str(private).unwrap();
97 let keypair: Keypair = private.into();
98
99 let VrfEvaluatorInput {
100 epoch_seed,
101 delegator_table,
102 global_slot,
103 total_currency,
104 staking_ledger_hash: _,
105 } = &vrf_evaluator_input;
106
107 let now = std::time::Instant::now();
108
109 let vrf_result = delegator_table
110 .iter()
111 .map(|(index, (pub_key, stake))| {
112 let vrf_input = VrfEvaluationInput {
113 producer_key: keypair.clone(),
114 global_slot: *global_slot,
115 epoch_seed: epoch_seed.clone(),
116 account_pub_key: pub_key.clone(),
117 delegator_index: *index,
118 delegated_stake: (*stake).into(),
119 total_currency: (*total_currency).into(),
120 };
121 let vrf_result = vrf::evaluate_vrf(vrf_input).unwrap();
123 if let VrfEvaluationOutput::SlotWon(_) = vrf_result {
132 return Some(vrf_result);
133 }
134 None
135 })
136 .collect::<Vec<_>>();
137
138 let elapsed = now.elapsed();
139 let slot = vrf_evaluator_input.global_slot;
140 let ndelegator = vrf_evaluator_input.delegator_table.len();
141 eprintln!("TOTAL vrf::evaluate_vrf: {elapsed:?} slot:{slot:?} ndelegators:{ndelegator:?}");
143 dbg!(vrf_result);
144 }
145}