Skip to content
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

[Perf] Avoid tx root derivation during block generation #2577

Open
wants to merge 3 commits into
base: staging
Choose a base branch
from

Conversation

vicsn
Copy link
Contributor

@vicsn vicsn commented Nov 21, 2024

Motivation

Transaction, deployment and execution root derivation take up 90% of compute of block generation when excluding transaction verification. Fortunately, the ids can be cached at practically 0 cost.

If this is approved, I'll also apply the change to to_unconfirmed_id and potentially other calls to to_deployment_id and to_execution_id.

Test Plan

  • Local network succeeds.
  • Deployed network with traffic succeeds.

@vicsn vicsn changed the title Avoid tx root derivation during block generation [Perf] Avoid tx root derivation during block generation Nov 22, 2024
@@ -105,6 +105,16 @@ impl<N: Network> Deployment<N> {
Ok(u64::try_from(self.to_bytes_le()?.len())?)
}

/// Returns the number of program functions in the deployment.
pub fn len(&self) -> usize {
Copy link
Collaborator

@ljedrz ljedrz Nov 25, 2024

Choose a reason for hiding this comment

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

is len making it obvious that this refers to the number of functions in the program? otherwise num_functions might be a better pick; the same comment applies to is_empty

Copy link
Contributor Author

@vicsn vicsn Nov 25, 2024

Choose a reason for hiding this comment

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

Indeed its a bit of an odd naming without context, though it is not unnatural. The Deployment contains just one vector which equals the number of functions/verifying_keys/certificates.

I mainly did this to have consistent naming with Execution::len, where it refers to the number of transitions. This PR then uses both deployment.len() and execution.len() to determine at which "index" to insert an additional Fee transition.

I'd be keen to hear more reviewer's thoughts on this.

Copy link
Contributor

Choose a reason for hiding this comment

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

Overall, I'd opt for a more precise naming for clarity. But this is fine as well.

Comment on lines +176 to +189
/// Returns the Merkle tree for the given execution tree and fee.
pub fn transaction_tree(
mut execution_tree: TransactionTree<N>,
fee_index: usize,
fee: &Fee<N>,
) -> Result<TransactionTree<N>> {
// Construct the transaction leaf.
let leaf = TransactionLeaf::new_fee(u16::try_from(fee_index)?, **fee.transition_id()).to_bits_le();
// Compute the transaction tree.
execution_tree.append(&[leaf])?;

Ok(execution_tree)
}

Copy link
Contributor

@raychu86 raychu86 Dec 6, 2024

Choose a reason for hiding this comment

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

There is now technically 2 paths to get a transaction tree, which can be a bit confusing.

  1. Creating a tree directly with a deployment/execution + fee
  2. Creating a deployment/execution tree and then concatenating the fee

Is there a way to unify these (where one relies on the other) into a single function? Also for safety, transaction_tree can be made private.

@raychu86
Copy link
Contributor

raychu86 commented Dec 6, 2024

Great find! We can save the construction of a depth 5 tree for each transaction.

My one note was exploring the possibility of a cleaner/more unified design.

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.

3 participants