openmina_node_common/service/block_producer/
vrf_evaluator.rs

1use 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 bytes = serde_json::to_string(&vrf_evaluator_input).unwrap();
21        // openmina_core::http::download("vrf.json".to_string(), bytes.as_bytes().to_vec()).unwrap();
22
23        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                // the first delegate that won the slot
48                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        // send the result back to the state machine
61        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 mina_signer::keypair;
85    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 now = redux::Instant::now();
122                let vrf_result = vrf::evaluate_vrf(vrf_input).unwrap();
123                // let elapsed = now.elapsed();
124                // let slot = global_slot;
125                // eprintln!("vrf::evaluate_vrf: {elapsed:?} slot:{slot:?} index:{index:?}");
126                // openmina_core::info!(openmina_core::log::system_time(); "vrf::evaluate_vrf: {elapsed:?} slot:{slot:?} index:{index:?}");
127
128                // nevaluated.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
129
130                // the first delegate that won the slot
131                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        // let nevaluated = nevaluated.load(std::sync::atomic::Ordering::Relaxed);
142        eprintln!("TOTAL vrf::evaluate_vrf: {elapsed:?} slot:{slot:?} ndelegators:{ndelegator:?}");
143        dbg!(vrf_result);
144    }
145}