1111// C'est la vie.
1212#[ cfg( feature = "alloc" ) ]
1313use alloc:: vec:: Vec ;
14+ #[ cfg( not( feature = "alloc" ) ) ]
15+ use internals:: array_vec:: ArrayVec ;
1416
15- #[ cfg( feature = "alloc" ) ]
1617use hashes:: { HashEngine , sha256d} ;
1718
18- #[ cfg( feature = "alloc" ) ]
1919use crate :: hash_types:: { Txid , Wtxid } ;
20- #[ cfg( feature = "alloc" ) ]
2120use crate :: transaction:: TxIdentifier ;
2221
2322#[ doc( inline) ]
@@ -32,7 +31,6 @@ pub use crate::hash_types::{TxMerkleNode, TxMerkleNodeEncoder, WitnessMerkleNode
3231///
3332/// Other Merkle trees in Bitcoin, such as those used in Taproot commitments,
3433/// do not use this algorithm and cannot use this trait.
35- #[ cfg( feature = "alloc" ) ]
3634pub ( crate ) trait MerkleNode : Copy + PartialEq {
3735 /// The hash (TXID or WTXID) of a transaction in the tree.
3836 type Leaf : TxIdentifier ;
@@ -50,13 +48,23 @@ pub(crate) trait MerkleNode: Copy + PartialEq {
5048 /// transactions will always be invalid, so there is no harm in us refusing to
5149 /// compute their merkle roots.
5250 ///
51+ /// Also returns `None` if the `alloc` feature is disabled and `iter` has more than
52+ /// 32,767 transactions.
53+ ///
5354 /// Unless you are certain your transaction list is nonempty and has no duplicates,
5455 /// you should not unwrap the `Option` returned by this method!
5556 fn calculate_root < I : Iterator < Item = Self :: Leaf > > ( iter : I ) -> Option < Self > {
5657 {
58+ #[ cfg( feature = "alloc" ) ]
5759 let mut stack = Vec :: < ( usize , Self ) > :: with_capacity ( 32 ) ;
60+ #[ cfg( not( feature = "alloc" ) ) ]
61+ let mut stack = ArrayVec :: < ( usize , Self ) , 15 > :: new ( ) ;
62+
5863 // Start with a standard Merkle tree root computation...
5964 for ( mut n, leaf) in iter. enumerate ( ) {
65+ #[ cfg( not( feature = "alloc" ) ) ]
66+ // This is the only time that the stack actually grows, rather than being combined.
67+ if stack. len ( ) == 15 { return None ; }
6068 stack. push ( ( 0 , Self :: from_leaf ( leaf) ) ) ;
6169
6270 while n & 1 == 1 {
@@ -106,7 +114,6 @@ pub(crate) trait MerkleNode: Copy + PartialEq {
106114// our hash traits, it should be possible to put bounds on `MerkleNode`
107115// and `MerkleNode::Leaf` which are sufficient to turn both methods into
108116// provided methods in the trait definition.
109- #[ cfg( feature = "alloc" ) ]
110117impl MerkleNode for TxMerkleNode {
111118 type Leaf = Txid ;
112119 fn from_leaf ( leaf : Self :: Leaf ) -> Self { Self :: from_byte_array ( leaf. to_byte_array ( ) ) }
@@ -118,7 +125,6 @@ impl MerkleNode for TxMerkleNode {
118125 Self :: from_byte_array ( sha256d:: Hash :: from_engine ( encoder) . to_byte_array ( ) )
119126 }
120127}
121- #[ cfg( feature = "alloc" ) ]
122128impl MerkleNode for WitnessMerkleNode {
123129 type Leaf = Wtxid ;
124130 fn from_leaf ( leaf : Self :: Leaf ) -> Self { Self :: from_byte_array ( leaf. to_byte_array ( ) ) }
@@ -133,19 +139,16 @@ impl MerkleNode for WitnessMerkleNode {
133139
134140#[ cfg( test) ]
135141mod tests {
136- #[ cfg( feature = "alloc" ) ]
137142 use crate :: hash_types:: * ;
138143
139144 // Helper to make a Txid, TxMerkleNode pair with a single number byte array
140- #[ cfg( feature = "alloc" ) ]
141145 fn make_leaf_node ( byte : u8 ) -> ( Txid , TxMerkleNode ) {
142146 let leaf = Txid :: from_byte_array ( [ byte; 32 ] ) ;
143147 let node = TxMerkleNode :: from_leaf ( leaf) ;
144148 ( leaf, node)
145149 }
146150
147151 #[ test]
148- #[ cfg( feature = "alloc" ) ]
149152 fn tx_merkle_node_single_leaf ( ) {
150153 let ( leaf, node) = make_leaf_node ( 1 ) ;
151154 let root = TxMerkleNode :: calculate_root ( [ leaf] . into_iter ( ) ) ;
@@ -154,7 +157,6 @@ mod tests {
154157 }
155158
156159 #[ test]
157- #[ cfg( feature = "alloc" ) ]
158160 fn tx_merkle_node_two_leaves ( ) {
159161 let ( leaf1, node1) = make_leaf_node ( 1 ) ;
160162 let ( leaf2, node2) = make_leaf_node ( 2 ) ;
@@ -169,7 +171,6 @@ mod tests {
169171 }
170172
171173 #[ test]
172- #[ cfg( feature = "alloc" ) ]
173174 fn tx_merkle_node_duplicate_leaves ( ) {
174175 let leaf = Txid :: from_byte_array ( [ 3 ; 32 ] ) ;
175176 // Duplicate transaction list should be rejected (CVE 2012‑2459).
@@ -178,13 +179,11 @@ mod tests {
178179 }
179180
180181 #[ test]
181- #[ cfg( feature = "alloc" ) ]
182182 fn tx_merkle_node_empty ( ) {
183183 assert ! ( TxMerkleNode :: calculate_root( [ ] . into_iter( ) ) . is_none( ) , "Empty iterator should return None" ) ;
184184 }
185185
186186 #[ test]
187- #[ cfg( feature = "alloc" ) ]
188187 fn tx_merkle_node_2n_minus_1_unbalanced_tree ( ) {
189188 // Test a tree with 2^n - 1 unique nodes and at least 3 layers deep.
190189 let ( leaf1, node1) = make_leaf_node ( 1 ) ;
@@ -243,7 +242,30 @@ mod tests {
243242 }
244243
245244 #[ test]
246- #[ cfg( feature = "alloc" ) ]
245+ fn tx_merkle_node_oversize_tree ( ) {
246+ // Confirm that with no-alloc, we return None for iter length >= 32768
247+ let root = TxMerkleNode :: calculate_root ( ( 0 ..32768u32 ) . map ( |i| {
248+ let mut buf = [ 0u8 ; 32 ] ;
249+ buf[ ..4 ] . copy_from_slice ( & i. to_le_bytes ( ) ) ;
250+ Txid :: from_byte_array ( buf)
251+ } ) ) ;
252+
253+ // We just want to confirm that we return None at the 32768 element boundary.
254+ #[ cfg( feature = "alloc" ) ]
255+ assert_ne ! ( root, None ) ;
256+ #[ cfg( not( feature = "alloc" ) ) ]
257+ assert_eq ! ( root, None ) ;
258+
259+ // Check just under the boundary
260+ let root = TxMerkleNode :: calculate_root ( ( 0 ..32767u32 ) . map ( |i| {
261+ let mut buf = [ 0u8 ; 32 ] ;
262+ buf[ ..4 ] . copy_from_slice ( & i. to_le_bytes ( ) ) ;
263+ Txid :: from_byte_array ( buf)
264+ } ) ) ;
265+ assert_ne ! ( root, None ) ;
266+ }
267+
268+ #[ test]
247269 fn witness_merkle_node_single_leaf ( ) {
248270 let leaf = Wtxid :: from_byte_array ( [ 1 ; 32 ] ) ;
249271 let root = WitnessMerkleNode :: calculate_root ( [ leaf] . into_iter ( ) ) ;
@@ -253,7 +275,6 @@ mod tests {
253275 }
254276
255277 #[ test]
256- #[ cfg( feature = "alloc" ) ]
257278 fn witness_merkle_node_duplicate_leaves ( ) {
258279 let leaf = Wtxid :: from_byte_array ( [ 2 ; 32 ] ) ;
259280 let root = WitnessMerkleNode :: calculate_root ( [ leaf, leaf] . into_iter ( ) ) ;
0 commit comments