linkspace/commons/
pow.rs

1use std::collections::VecDeque;
2
3pub const POW_DOMAIN: Domain = abf(b"proof-of-work");
4
5use anyhow::ensure;
6use linkspace_core::point::*;
7
8use crate::point::lk_linkpoint_ref;
9
10pub fn lkc_pow_proof<R>(
11    leading_zeros: usize,
12) -> impl FnMut(&dyn Point, &mut dyn FnMut(&dyn Point) -> R) -> Option<R> {
13    let mut todo = 1;
14    let mut links = vec![];
15    move |p, cb| {
16        links.push(Link::new(now().0, p.hash()));
17        if links.len() < todo {
18            return None;
19        };
20        let mut data = now();
21        let mut proof_p;
22        loop {
23            data = data.incr();
24            proof_p = lk_linkpoint_ref(POW_DOMAIN, PUBLIC, LkPath::EMPTY, &data.0, &links, now())
25                .unwrap();
26            if proof_p.hash_ref().leading_zeros() >= leading_zeros {
27                break;
28            };
29        }
30        let ret = cb(&proof_p);
31        links.clear();
32        todo = 1024.min(todo * 2);
33        Some(ret)
34    }
35}
36pub fn lkc_pow_check(
37    leading_zeros: usize,
38) -> impl FnMut(&dyn Point) -> anyhow::Result<Option<&dyn Point>> {
39    let mut at = 0;
40    let mut checking = VecDeque::<Link>::new();
41    move |point| match checking.pop_front() {
42        Some(h) => {
43            ensure!(point.hash() == h.ptr);
44            Ok(Some(point))
45        }
46        None => {
47            ensure!(*point.get_domain() == POW_DOMAIN);
48            ensure!(point.hash_ref().leading_zeros() >= leading_zeros);
49            ensure!(point.get_links().len() == (at * 2).min(1024));
50            checking = point.get_links().to_vec().into();
51            at = checking.len();
52            Ok(None)
53        }
54    }
55}