RFC: bee-pow crate - #19
Conversation
| tester: T, | ||
| } | ||
|
|
||
| impl<H, S, T, D, R> PearlDiver<H, S, T, D, R> |
There was a problem hiding this comment.
As long as I pretty love these trait layers, I feel like generics in PearlDiver is a little bit out of hand. Would it be better to use trait object in this case? Don't get me wrong, I actually prefer static dispatch over dynamic. Just wanna bring some suggestions and see if it fits in. I would like to hear others' opinion between trait bound and trait objects.
| impl<H, S, T, D, R> PearlDiver<H, S, T, D, R> | |
| struct PearlDiver<D, R> { | |
| hasher: Box<dyn Hasher<Data = D, Hash = R>>, | |
| sampler: Box<dyn Sampler<Data = D>>, | |
| tester: Box<dyn Tester<Hash = R>>, | |
| } |
| The `Sampler` trait allows implementing different types that mutate the input data handed to the hasher on each try. The standard sampler used in IOTA simply starts with a zero nonce and increments it until it finds a valid one. There are, however, other samplers possible, like a random sampler. | ||
|
|
||
| ```Rust | ||
| pub trait Sampler { |
There was a problem hiding this comment.
Not sure where to put this comment, so it'll be here. The proposed design is not very well suited for data-parallel (using SIMD instructions) instances. At the moment fastest hashcash and pearldiver implementations use PCurl, which is "parallel" Curl capable of hashing n data/transactions (where n=64..256) at once. Of course, Sampler::Data can encapsulate such data-parallelism, but in my opinion it's not very convenient and it's worth baking it into the traits.
| pub trait Sampler { | ||
| type Data; | ||
|
|
||
| fn next(&mut self, data: &mut Self::Data); |
There was a problem hiding this comment.
next should have bool as return type and return false in case the search data is exhausted. In real world cases we'll hardly exhaust it but it might be useful in tests and as additional guarantees that PoW doesn't loop infinitely.
| ```Rust | ||
| pub trait Sampler { | ||
| type Data; | ||
|
|
There was a problem hiding this comment.
Again, from my experience in hashcash and pearldiver the search data should be prepared in some non-trivial way (mostly, in order to guarantee that parallel ranges do not overlap). I would consider something like this:
type Data;
type SearchData;
fn prepare(&mut self, data: &Self::Data, search_data: &mut Self::SearchData);
fn next(&mut self, search_data: &mut Self::SearchData) -> bool;There was a problem hiding this comment.
very good input, thanks. I will think about this more.
Am I correct in assuming that by "prepared in some non-trivial way" you mean conversion from t1b1 to ptrits (vectorizing) ?
| whereby | ||
|
|
||
| ```Rust | ||
| pub type PoWError = Box<dyn std::error::Error>; |
There was a problem hiding this comment.
Is there any particular reason that PoWError must be dynamically-allocated?
There was a problem hiding this comment.
I think not. Any suggestion?
344f731 to
60e695c
Compare
Rendered