wip-incremental #4
4 changed files with 121 additions and 3 deletions
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
|
@ -42,7 +42,7 @@ jobs:
|
|||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --all --bins --examples --tests
|
||||
args: --all --bins --examples --tests --all-features
|
||||
|
||||
- name: tests
|
||||
uses: actions-rs/cargo@v1
|
||||
|
@ -56,7 +56,7 @@ jobs:
|
|||
uses: actions-rs/tarpaulin@v0.1
|
||||
with:
|
||||
version: '0.15.0'
|
||||
args: '-t 1200'
|
||||
args: '-t 1200 --all-features'
|
||||
|
||||
- name: Upload to Codecov
|
||||
if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
|
||||
|
|
|
@ -19,3 +19,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||
bincode = "1.3"
|
||||
derive_builder = "0.12"
|
||||
num = { version = "0.4.0", default-features = false, features = ["serde", "num-bigint"]}
|
||||
|
||||
[features]
|
||||
default = []
|
||||
incremental = []
|
||||
|
|
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
define test_core
|
||||
cargo test --no-fail-fast
|
||||
cargo test --no-fail-fast --all-features
|
||||
endef
|
||||
|
||||
default: ## Build library in debug mode
|
||||
|
|
114
src/lib.rs
114
src/lib.rs
|
@ -50,7 +50,94 @@ pub struct Config {
|
|||
pub salt: String,
|
||||
}
|
||||
|
||||
/// Return value of incremental prooving. When proof is ready, IncrementalSolve::Work is returned
|
||||
/// and when proof is not ready, IncrementalSolve::Intermediate is returned
|
||||
#[cfg(feature = "incremental")]
|
||||
pub enum IncrementalSolve<T> {
|
||||
/// Intermediate result
|
||||
Intermediate(u128, u64, Sha256, u128),
|
||||
/// Final result
|
||||
Work(PoW<T>),
|
||||
}
|
||||
|
||||
impl Config {
|
||||
///
|
||||
/// step is used to control the number of cycles after which the function should exit, even
|
||||
/// when the proof isn't ready
|
||||
/// inter is used to keep track of state and complete proof generation. Set inter to None
|
||||
/// during first cyle and pass the returned value of the previous cycle to continue proof
|
||||
/// generation
|
||||
|
||||
#[cfg(feature = "incremental")]
|
||||
pub fn stepped_prove_work<T>(
|
||||
&self,
|
||||
t: &T,
|
||||
difficulty: u32,
|
||||
step: usize,
|
||||
inter: Option<IncrementalSolve<T>>,
|
||||
) -> bincode::Result<IncrementalSolve<T>>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
bincode::serialize(t)
|
||||
.map(|v| self.stepped_prove_work_serialized(&v, difficulty, step, inter))
|
||||
}
|
||||
|
||||
#[cfg(feature = "incremental")]
|
||||
/// Create Proof of Work over item of type T.
|
||||
///
|
||||
/// Make sure difficulty is not too high. A 64 bit difficulty,
|
||||
/// for example, takes a long time on a general purpose processor.
|
||||
/// The input is assumed to be serialized using network byte order.
|
||||
///
|
||||
/// Make sure difficulty is not too high. A 64 bit difficulty,
|
||||
/// for example, takes a long time on a general purpose processor.
|
||||
/// step is used to control the number of cycles after which the function should exit, even
|
||||
/// when the proof isn't ready
|
||||
/// inter is used to keep track of state and complete proof generation. Set inter to None
|
||||
/// during first cyle and pass the returned value of the previous cycle to continue proof
|
||||
/// generation
|
||||
/// Returns bincode::Error if serialization fails.
|
||||
/// Create Proof of Work on an already serialized item of type T.
|
||||
fn stepped_prove_work_serialized<T>(
|
||||
&self,
|
||||
prefix: &[u8],
|
||||
difficulty: u32,
|
||||
step: usize,
|
||||
inter: Option<IncrementalSolve<T>>,
|
||||
) -> IncrementalSolve<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let (mut result, mut n, prefix_sha, difficulty) = match inter {
|
||||
Some(IncrementalSolve::Intermediate(result, nonce, prefix, difficulty)) => {
|
||||
(result, nonce, prefix, difficulty)
|
||||
}
|
||||
_ => {
|
||||
let prefix_sha = Sha256::new().chain(&self.salt).chain(prefix);
|
||||
let n = 0;
|
||||
let result = 0;
|
||||
let difficulty = get_difficulty(difficulty);
|
||||
(result, n, prefix_sha, difficulty)
|
||||
}
|
||||
};
|
||||
let mut count = 0;
|
||||
while result < difficulty {
|
||||
if count > step {
|
||||
return IncrementalSolve::Intermediate(result, n, prefix_sha, difficulty);
|
||||
} else {
|
||||
count += 1;
|
||||
}
|
||||
n += 1;
|
||||
result = dev::score(prefix_sha.clone(), n);
|
||||
}
|
||||
IncrementalSolve::Work(PoW {
|
||||
nonce: n,
|
||||
result: result.to_string(),
|
||||
_spook: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create Proof of Work over item of type T.
|
||||
///
|
||||
/// Make sure difficulty is not too high. A 64 bit difficulty,
|
||||
|
@ -262,4 +349,31 @@ mod test {
|
|||
assert!(config.is_sufficient_difficulty(&message.1, DIFFICULTY));
|
||||
assert!(config.is_valid_proof(&message.1, &target));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "incremental")]
|
||||
fn stepped_solve() {
|
||||
let phrase = "Ex nihilo nihil fit.".to_owned();
|
||||
let config = get_config();
|
||||
|
||||
let mut inter = None;
|
||||
loop {
|
||||
match config.stepped_prove_work(&phrase, 50000, 1000, inter) {
|
||||
Ok(IncrementalSolve::Intermediate(result, nonce, prefix, difficulty)) => {
|
||||
println!("Current nonce {nonce}");
|
||||
inter = Some(IncrementalSolve::Intermediate(
|
||||
result, nonce, prefix, difficulty,
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
Ok(IncrementalSolve::Work(w)) => {
|
||||
assert!(config.is_valid_proof(&w, &phrase));
|
||||
assert!(config.is_sufficient_difficulty(&w, DIFFICULTY));
|
||||
break;
|
||||
}
|
||||
Err(e) => panic!("{}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue