-
Notifications
You must be signed in to change notification settings - Fork 1.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
[Perf] Avoid tx root derivation during block generation #2577
base: staging
Are you sure you want to change the base?
[Perf] Avoid tx root derivation during block generation #2577
Conversation
@@ -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 { |
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.
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
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.
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.
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.
Overall, I'd opt for a more precise naming for clarity. But this is fine as well.
/// 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) | ||
} | ||
|
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.
There is now technically 2 paths to get a transaction tree, which can be a bit confusing.
- Creating a tree directly with a deployment/execution + fee
- 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.
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. |
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 toto_deployment_id
andto_execution_id
.Test Plan