Skip to content

feat: adjustable pow difficulty#865

Merged
SantiagoPittella merged 51 commits intonextfrom
santiagopittella-adjustable-pow-difficulty
May 28, 2025
Merged

feat: adjustable pow difficulty#865
SantiagoPittella merged 51 commits intonextfrom
santiagopittella-adjustable-pow-difficulty

Conversation

@SantiagoPittella
Copy link
Collaborator

@SantiagoPittella SantiagoPittella commented May 22, 2025

closes #854

Copy link
Collaborator

@TomasArrachea TomasArrachea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

#[derive(Clone)]
pub struct PoW {
pub(crate) salt: String,
pub(crate) difficulty: Arc<Mutex<u64>>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's worth it but we could try AtomicU64 here. Otherwise i would use tokio::sync::Mutex instead of std::sync::Mutex

}

impl PoW {
pub fn adjust_difficulty(&mut self, sender_count: usize) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could add a doc comment on how this difficulty is adjusted to the faucet load

@bobbinth bobbinth requested review from igamigo and sergerad May 26, 2025 02:29
Comment on lines +24 to +25
/// The difficulty is the number of leading zeros in the hash of the seed and the solution.
const DIFFICULTY: u64 = 5;
const MAX_DIFFICULTY: u64 = 6;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Max difficulty of 6 leading zeros seems pretty low (i.e., it would require, on average, 64 guesses to get the right nonce). A moderately-powerful machine should be able to guess 16 leading zeros in under a second, and 20 leading zeros within a few seconds). I'd probably set the maximum at something like 24.

Also, as mentioned in another comment, ideally, PoW should be based not on the number of leading zeros but on absolute values. This way, it can be adjusted more granularly - but we can do this in a separate PR.

Base automatically changed from santiagopittella-stateful-signatures to next May 26, 2025 18:47
@SantiagoPittella SantiagoPittella requested a review from bobbinth May 26, 2025 20:53
Copy link
Collaborator

@igamigo igamigo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Left some comments/questions

CHANGELOG.md Outdated
- Added an optional API key request parameter to skip PoW in faucet (#839).
- Block producer now emits network note information (#833).
- Introduced Network Transaction Builder (#840).
- Proof-of-Work difficulty is now adjustable based on the number of concurrent requests (#865).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit (feel free to disregard):

Suggested change
- Proof-of-Work difficulty is now adjustable based on the number of concurrent requests (#865).
- Proof-of-Work difficulty is now adjusted based on the number of concurrent requests (#865).

Query(request): Query<RawMintRequest>,
) -> Sse<impl Stream<Item = Result<Event, Infallible>>> {
let request_guard =
RequestCounterGuard::new(server.active_requests.clone(), server.queued_requests.clone());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: You can take &Arc<_> in RequestCounterGuard::new() and clone internally for a slightly more ergonomic API here

/// The difficulty is adjusted based on the number of active requests.
/// The difficulty is increased by 1 for every 50 active requests.
/// The difficulty is clamped between 1 and `MAX_DIFFICULTY`.
pub fn adjust_difficulty(&self, active_requests: usize) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now if we go back (for example) to a max queue of 200 requests the effective max difficulty is 4, right? If not, disregard this comment.

But otherwise, and maybe not for now, should this function take into account the max queue length somehow?
For example, we could map the queue length into the difficulty range by computing the filled ration of the queue and applying that to the [1..MAX_DIFFICULTY] range. This way the step interval (50 in this case) is not "coupled" with the queue length in any way and we could tweak difficulty or max queue length and expect it to work linearly (or we could decide to grow it exponentially, etc.).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just saw that the difficulty is adjusted based on total requests (even if the PoW does not validate), not just minting requests in progress. I was expecting it to be over the requests that validated correctly, but I think this might be fine and maybe dismisses my comment above. Not entirely sure if there is a practical difference.

In any case, would it make sense to make the step interval be configurable? Maybe as part of #878

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced this logic, basically increasing the difficulty every step defined by REQUEST_QUEUE_SIZE / MAX_DIFFICULTY

///
/// The difficulty is the number of leading zeros in the hash of the seed and the solution.
const DIFFICULTY: u64 = 5;
const MAX_DIFFICULTY: u64 = 24;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to my previous comment, since the max queue length is 1000 (AFAIK, maybe something changed or I'm missing something else), I think the effective max difficulty would be 20 here.

@SantiagoPittella SantiagoPittella requested a review from sergerad May 27, 2025 14:39
@SantiagoPittella SantiagoPittella merged commit 63f4975 into next May 28, 2025
6 checks passed
@SantiagoPittella SantiagoPittella deleted the santiagopittella-adjustable-pow-difficulty branch May 28, 2025 14:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

faucet(PoW): adjust difficulty

5 participants