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}