1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
//! Verifier implementation for v1 client puzzles
use crate::v1::challenge::Challenge;
use crate::v1::{Instance, RuntimeError, RuntimeOption, Solution, SolutionError};
use crate::Error;
use equix::{EquiXBuilder, HashError};
/// Checker for potential [`Solution`]s to a particular puzzle [`Instance`]
///
/// Holds information about the puzzle instance, and optional configuration
/// settings.
pub struct Verifier {
/// The puzzle instance we're verifying
instance: Instance,
/// Configuration settings for Equi-X, as an [`EquiXBuilder`] instance
equix: EquiXBuilder,
}
impl Verifier {
/// Construct a new [`Verifier`] by wrapping an [`Instance`].
pub fn new(instance: Instance) -> Self {
Self {
instance,
equix: Default::default(),
}
}
/// Select the HashX runtime to use for this verifier.
///
/// By default, uses [`RuntimeOption::TryCompile`]
pub fn runtime(&mut self, option: RuntimeOption) -> &mut Self {
self.equix.runtime(option);
self
}
/// Check whether a solution is valid for this puzzle instance.
///
/// May return a [`SolutionError`] or a [`RuntimeError`]
pub fn check(&self, solution: &Solution) -> Result<(), Error> {
match self.check_seed(solution) {
Err(e) => Err(Error::BadSolution(e.into())),
Ok(()) => {
let challenge = Challenge::new(&self.instance, solution.effort(), solution.nonce());
match challenge.check_effort(&solution.proof_to_bytes()) {
Err(e) => Err(Error::BadSolution(e.into())),
Ok(()) => match self.equix.verify(challenge.as_ref(), solution.proof()) {
Ok(()) => Ok(()),
Err(equix::Error::HashSum) => {
Err(Error::BadSolution(SolutionError::HashSum.into()))
}
Err(equix::Error::Hash(HashError::ProgramConstraints)) => Err(
Error::BadSolution(SolutionError::ChallengeConstraints.into()),
),
Err(e) => Err(Error::VerifyRuntime(RuntimeError::EquiX(e).into())),
},
}
}
}
}
/// Check the [`super::SeedHead`] of a solution against an [`Instance`].
///
/// This is a very cheap test, this should come first so a service
/// can verify every [`Solution`] against its last two [`Instance`]s.
fn check_seed(&self, solution: &Solution) -> Result<(), SolutionError> {
if solution.seed_head() == self.instance.seed().head() {
Ok(())
} else {
Err(SolutionError::Seed)
}
}
}
|