-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Improves safety & readability on transaction root derivation logic #2668
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
Changes from 6 commits
02cfd23
ea65a1c
cb61dcc
9b333ed
3378104
4d9cee1
266fbff
0236435
2eea916
05f30a5
493f29f
bfa667f
13afd8e
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 |
|---|---|---|
|
|
@@ -93,17 +93,11 @@ impl<N: Network> Transaction<N> { | |
| match self { | ||
| // Compute the deployment tree. | ||
| Transaction::Deploy(_, _, _, deployment, fee) => { | ||
| let deployment_tree = Self::deployment_tree(deployment)?; | ||
| Self::transaction_tree(deployment_tree, deployment.len(), fee) | ||
| Self::transaction_tree(Self::deployment_tree(deployment)?, Some(fee)) | ||
| } | ||
| // Compute the execution tree. | ||
| Transaction::Execute(_, _, execution, fee) => { | ||
| let execution_tree = Self::execution_tree(execution)?; | ||
| if let Some(fee) = fee { | ||
| Ok(Transaction::transaction_tree(execution_tree, execution.len(), fee)?) | ||
| } else { | ||
| Ok(execution_tree) | ||
| } | ||
| Self::transaction_tree(Self::execution_tree(execution)?, fee.as_ref()) | ||
| } | ||
| // Compute the fee tree. | ||
| Transaction::Fee(_, fee) => Self::fee_tree(fee), | ||
|
|
@@ -112,6 +106,30 @@ impl<N: Network> Transaction<N> { | |
| } | ||
|
|
||
| impl<N: Network> Transaction<N> { | ||
| /// Returns the Merkle tree for the given transaction tree, fee index, and fee. | ||
| pub fn transaction_tree( | ||
| mut deployment_or_execution_tree: TransactionTree<N>, | ||
| fee: Option<&Fee<N>>, | ||
| ) -> Result<TransactionTree<N>> { | ||
| // If a fee is provided, append the fee leaf to the transaction tree. | ||
| if let Some(fee) = fee { | ||
| // Retrieve the fee index, defined as the last index in the transaction tree. | ||
| let fee_index = deployment_or_execution_tree.number_of_leaves(); | ||
| // Ensure the fee index is within the Merkle tree size. | ||
| ensure!( | ||
| fee_index < Self::MAX_TRANSITIONS, | ||
|
Collaborator
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 you want to bound it based on the transaction type, then Right now we keep them all at 2^5, but if any are changed in the future, this check may not be correct.
Member
Author
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. Good point. As this method could contain either a deployment tree OR an execution tree, should I check both
Collaborator
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. It's probably a good idea to do both checks. Alternatively, because we always know what type of tree we are passing into this function, we can do a conditional check (using a boolean or const generic)
Contributor
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. Do we want the check Do
Member
Author
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.
Member
Author
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. |
||
| "The fee index ('{fee_index}') in the transaction tree must be less than {}", | ||
| Self::MAX_TRANSITIONS | ||
| ); | ||
| // Construct the transaction leaf. | ||
| let leaf = TransactionLeaf::new_fee(u16::try_from(fee_index)?, **fee.transition_id()).to_bits_le(); | ||
| // Append the fee leaf to the transaction tree. | ||
| deployment_or_execution_tree.append(&[leaf])?; | ||
| } | ||
| // Return the transaction tree. | ||
| Ok(deployment_or_execution_tree) | ||
| } | ||
|
|
||
| /// Returns the Merkle tree for the given deployment. | ||
| pub fn deployment_tree(deployment: &Deployment<N>) -> Result<DeploymentTree<N>> { | ||
| // Ensure the number of leaves is within the Merkle tree size. | ||
|
|
@@ -123,22 +141,16 @@ impl<N: Network> Transaction<N> { | |
| Some(program_checksum) => program_checksum.to_bits_le(), | ||
| }; | ||
| // Prepare the leaves. | ||
| let leaves = deployment | ||
| .program() | ||
| .functions() | ||
| .values() | ||
| .enumerate() | ||
| .map(|(index, function)| { | ||
| // Construct the transaction leaf. | ||
| Ok(TransactionLeaf::new_deployment( | ||
| u16::try_from(index)?, | ||
| N::hash_bhp1024(&to_bits_le![header, function.to_bytes_le()?])?, | ||
| ) | ||
| .to_bits_le()) | ||
| }) | ||
| .collect::<Result<Vec<_>>>()?; | ||
| let leaves = deployment.program().functions().values().enumerate().map(|(index, function)| { | ||
|
raychu86 marked this conversation as resolved.
Outdated
|
||
| // Construct the transaction leaf. | ||
| Ok(TransactionLeaf::new_deployment( | ||
| u16::try_from(index)?, | ||
| N::hash_bhp1024(&to_bits_le![header, function.to_bytes_le()?])?, | ||
| ) | ||
| .to_bits_le()) | ||
| }); | ||
| // Compute the deployment tree. | ||
| N::merkle_tree_bhp::<TRANSACTION_DEPTH>(&leaves) | ||
| N::merkle_tree_bhp::<TRANSACTION_DEPTH>(&leaves.collect::<Result<Vec<_>>>()?) | ||
| } | ||
|
|
||
| /// Returns the Merkle tree for the given execution. | ||
|
|
@@ -155,29 +167,12 @@ impl<N: Network> Transaction<N> { | |
| // Ensure the number of leaves is within the Merkle tree size. | ||
| Self::check_execution_size(num_transitions)?; | ||
| // Prepare the leaves. | ||
| let leaves = transitions | ||
| .enumerate() | ||
| .map(|(index, transition)| { | ||
| // Construct the transaction leaf. | ||
| Ok::<_, Error>(TransactionLeaf::new_execution(u16::try_from(index)?, **transition.id()).to_bits_le()) | ||
| }) | ||
| .collect::<Result<Vec<_>, _>>()?; | ||
| let leaves = transitions.enumerate().map(|(index, transition)| { | ||
| // Construct the transaction leaf. | ||
| Ok::<_, Error>(TransactionLeaf::new_execution(u16::try_from(index)?, **transition.id()).to_bits_le()) | ||
| }); | ||
| // Compute the execution tree. | ||
| N::merkle_tree_bhp::<TRANSACTION_DEPTH>(&leaves) | ||
| } | ||
|
|
||
| /// Returns the Merkle tree for the given 1. transaction or deployment tree and 2. fee. | ||
| pub fn transaction_tree( | ||
| mut deployment_or_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 updated transaction tree. | ||
| deployment_or_execution_tree.append(&[leaf])?; | ||
|
|
||
| Ok(deployment_or_execution_tree) | ||
| N::merkle_tree_bhp::<TRANSACTION_DEPTH>(&leaves.collect::<Result<Vec<_>, _>>()?) | ||
| } | ||
|
|
||
| /// Returns the Merkle tree for the given fee. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.