-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Optimize] Add guards for processing unconfirmed solutions #3225
Changes from all commits
4ae5926
0eef8ed
bdfb225
877bf7f
67a5fdd
244fc00
7d34635
55c8a6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -313,6 +313,11 @@ impl<N: Network, C: ConsensusStorage<N>, R: Routing<N>> Rest<N, C, R> { | |
State(rest): State<Self>, | ||
Json(tx): Json<Transaction<N>>, | ||
) -> Result<ErasedJson, RestError> { | ||
// Do not process the transaction if the node is syncing. | ||
if !rest.routing.is_block_synced() { | ||
return Err(RestError(format!("Unable to broadcast transaction '{}' (node is syncing)", fmt_id(tx.id())))); | ||
} | ||
|
||
// If the consensus module is enabled, add the unconfirmed transaction to the memory pool. | ||
if let Some(consensus) = rest.consensus { | ||
// Add the unconfirmed transaction to the memory pool. | ||
|
@@ -337,10 +342,38 @@ impl<N: Network, C: ConsensusStorage<N>, R: Routing<N>> Rest<N, C, R> { | |
State(rest): State<Self>, | ||
Json(solution): Json<Solution<N>>, | ||
) -> Result<ErasedJson, RestError> { | ||
// Do not process the solution if the node is syncing. | ||
if !rest.routing.is_block_synced() { | ||
return Err(RestError(format!( | ||
"Unable to broadcast solution '{}' (node is syncing)", | ||
fmt_id(solution.id()) | ||
))); | ||
} | ||
|
||
// If the consensus module is enabled, add the unconfirmed solution to the memory pool. | ||
if let Some(consensus) = rest.consensus { | ||
// Otherwise, verify it prior to broadcasting. | ||
match rest.consensus { | ||
// Add the unconfirmed solution to the memory pool. | ||
consensus.add_unconfirmed_solution(solution).await?; | ||
Some(consensus) => consensus.add_unconfirmed_solution(solution).await?, | ||
// Verify the solution. | ||
None => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If clients receive transactions/solutions via P2P, they are already verified before propagation in For consistency and clarity, we should also do this for transactions. A solution takes longer to verify than an execution, but less than a deployment, so there's no difference justifying a different verification approach. Recall this PR was triggered in part because recently we did a large invalid solution spam, but @iamalwaysuncomfortable and I just realized we never tried spamming very large amounts of invalid transactions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR also remains relevant in the face of solution or deployment spam: https://github.com/AleoHQ/snarkOS/pull/2970 |
||
// Compute the current epoch hash. | ||
let epoch_hash = rest.ledger.latest_epoch_hash()?; | ||
// Retrieve the current proof target. | ||
let proof_target = rest.ledger.latest_proof_target(); | ||
// Ensure that the solution is valid for the given epoch. | ||
let puzzle = rest.ledger.puzzle().clone(); | ||
// Verify the solution in a blocking task. | ||
match tokio::task::spawn_blocking(move || puzzle.check_solution(&solution, epoch_hash, proof_target)) | ||
.await | ||
{ | ||
Ok(Ok(())) => {} | ||
Ok(Err(err)) => { | ||
return Err(RestError(format!("Invalid solution '{}' - {err}", fmt_id(solution.id())))); | ||
} | ||
Err(err) => return Err(RestError(format!("Invalid solution '{}' - {err}", fmt_id(solution.id())))), | ||
} | ||
} | ||
} | ||
|
||
let solution_id = solution.id(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can imagine spamming a publicly accessible REST endpoint with solutions could halt a client due to the amount of verifications required. But we should test (cc @iamalwaysuncomfortable).
If it turns out to be an issue, we can:
.layer(GovernorLayer { }
.